You have one class doing work that should be done by two.
Create a new class and move the relevant fields and methods from the old class into the new class.
Complexity
easy
You might have heard that classes should have a single responsibility. Even if you try to follow this dogma, in practice classes grow. Some operations are, some more data is added, and sooner or later your class has more than one reponsibility.
The Extract Class refactoring is best applied if there are logical units of data which are grouped together, or operations which are just performed on a subset of the data.
Let’s assume the following class:
class BlogPost { // ... private $previewTextRst; private $previewTextHtml; private $textRst; private $textHtml; // ... public function setPreviewText($rst, $html) { $this->previewTextRst = $rst; $this->previewTextHtml = $html; } public function setText($rst, $html) { $this->textRst = $rst; $this->textHtml = $html; } // ... }
As you can see, we have two sets of fields which are grouped together and some operations which only perform work on a specific subset of fields. In this example, it is very obvious since we also have some duplication which we can reduce by extracting a class.
We will continue by introducing a new Text
class and move the textRst
and textHtml
fields to it:
class Text { private $rst; private $html; public function __construct($rst, $html) { $this->rst = $rst; $this->html = $html; } public function getRst() { return $this->rst; } public function getHtml() { return $this->html; } } class BlogPost { private $previewText; private $text; public function setPreviewText($rst, $html) { $this->previewText = new Text($rst, $html); } public function setText($rst, $html) { $this->text = new Text($rst, $html); } }
In our case, the name of the old class is still fitting, we do not need to rename it. So, we will just skip this step.
Our classes only have a unidirectional link, the Text
class does not know
where it is being used, and it also does not need to know. This also allows us
to use the Text
class in classes other than BlogPost
. So, there is
nothing to change here as well.
In general, prefer to use a value object as this limits the scope of how and
when the object can be modified. In our case, we decided to use a value object:
If the text is changed, a new object must be created. This way we ensure that
any modification must go through the owning class, in our case BlogPost
.
Checklists present a proven order of necessary refactoring steps and are especially helpful for beginners.
If you feel comfortable with a refactoring, there is no need to follow each of the steps literally; you can often perform multiple steps at once or skip some.
We suggest to try the recommended order at least once; this will often provide new insights - even for seasoned developers.