This question is based on two premises:
- First: an object must always have valid state. It is discussed in various posts, too. https://stackoverflow.com/questions/22408804/should-a-c-object-always-be-in-a-valid-state
- Second: a class can exclusively trust itself to anticipate as to whether its instances will have valid state.
There are some consequences to this such as: don't use public or protected properties. It is simple to understand why they should be avoided. There exist posts about this specific topic, too. Why is Clean Code suggesting avoiding protected variables?
Another consequence is that the this
reference should not be given to methods from other classes: http://www.ibm.com/developerworks/java/library/j-jtp0618/index.html#2 At least, it is often advised not to do so in constructors.
However, strictly speaking, wouldn't this prohibit almost every instance of passing this
to any dependency's methods? After all, unless a class is not part of a class hierarchy, how can it avoid that an object holds invalid state when passing this
?
An example in PHP:
class ClientCodeClass {
public function carryOutTask(ParentClass $object) {
// Client code now has access to the object in illegal state and things may mishappen because of that.
}
}
class ParentClass {
private $client_code_class;
public function __construct(ClientCodeClass $client_code_class) {
$this->client_code_class = $client_code_class;
}
protected function exposeParentClass() {
// At this time, $this is in invalid state, and we're passing it to client code!
$this->client_code_class->carryOutTask($this);
}
}
class ChildClass extends ParentClass {
public function doSomething() {
$this->setIllegalState();
$this->exposeParentClass();
$this->setLegalState();
}
}
$child_class = new ChildClass();
$child_class->doSomething();
So my question is: is it true that my two premises are correct and that they would be violated if a class (unless it does not extend another class and is marked final
) passes this
to a method of another object?
Follow up question: doesn't this also drastically restrict the allowed usage of callbacks? After all, when an object invokes the callback it can not guarantee that it is valid - while that callback could be working on that very object.