Complex classes like Base often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Base, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
20 | class Base |
||
21 | { |
||
22 | private $view; |
||
23 | private $context; |
||
24 | private $templatePaths; |
||
25 | private $path; |
||
26 | |||
27 | |||
28 | /** |
||
29 | * Initializes the client |
||
30 | * |
||
31 | * @param \Aimeos\MShop\Context\Item\Iface $context MShop context object |
||
32 | * @param \Aimeos\MW\View\Iface $view View object |
||
33 | * @param array $templatePaths List of file system paths where the templates are stored |
||
34 | * @param string $path Name of the client separated by slashes, e.g "product/stock" |
||
35 | */ |
||
36 | public function __construct( \Aimeos\MShop\Context\Item\Iface $context, \Aimeos\MW\View\Iface $view, array $templatePaths, $path ) |
||
43 | |||
44 | |||
45 | /** |
||
46 | * Returns the items with parent/child relationships |
||
47 | * |
||
48 | * @param array $items List of items implementing \Aimeos\MShop\Common\Item\Iface |
||
49 | * @param array $include List of resource types that should be fetched |
||
50 | * @return array List of items implementing \Aimeos\MShop\Common\Item\Iface |
||
51 | */ |
||
52 | protected function getChildItems( array $items, array $include ) |
||
56 | |||
57 | |||
58 | /** |
||
59 | * Returns the context item object |
||
60 | * |
||
61 | * @return \Aimeos\MShop\Context\Item\Iface Context object |
||
62 | */ |
||
63 | protected function getContext() |
||
67 | |||
68 | |||
69 | /** |
||
70 | * Returns the list of domains that are available as resources |
||
71 | * |
||
72 | * @param \Aimeos\MW\View\Iface $view View object with "resource" parameter |
||
73 | * @return array List of domain names |
||
74 | */ |
||
75 | protected function getDomains( \Aimeos\MW\View\Iface $view ) |
||
104 | |||
105 | |||
106 | /** |
||
107 | * Returns the IDs sent in the request body |
||
108 | * |
||
109 | * @param \stdClass $request Decoded request body |
||
110 | * @return array List of item IDs |
||
111 | */ |
||
112 | protected function getIds( $request ) |
||
128 | |||
129 | |||
130 | /** |
||
131 | * Returns the list items for association relationships |
||
132 | * |
||
133 | * @param array $items List of items implementing \Aimeos\MShop\Common\Item\Iface |
||
134 | * @param array $include List of resource types that should be fetched |
||
135 | * @return array List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface |
||
136 | */ |
||
137 | protected function getListItems( array $items, array $include ) |
||
141 | |||
142 | |||
143 | /** |
||
144 | * Returns the path to the client |
||
145 | * |
||
146 | * @return string Client path, e.g. "product/property" |
||
147 | */ |
||
148 | protected function getPath() |
||
152 | |||
153 | |||
154 | /** |
||
155 | * Returns the items associated via a lists table |
||
156 | * |
||
157 | * @param array $listItems List of items implementing \Aimeos\MShop\Common\Item\Lists\Iface |
||
158 | * @return array List of items implementing \Aimeos\MShop\Common\Item\Iface |
||
159 | */ |
||
160 | protected function getRefItems( array $listItems ) |
||
181 | |||
182 | |||
183 | /** |
||
184 | * Returns the paths to the template files |
||
185 | * |
||
186 | * @return array List of file system paths |
||
187 | */ |
||
188 | protected function getTemplatePaths() |
||
192 | |||
193 | |||
194 | /** |
||
195 | * Returns the view object |
||
196 | * |
||
197 | * @return \Aimeos\MW\View\Iface View object |
||
198 | */ |
||
199 | protected function getView() |
||
203 | |||
204 | |||
205 | /** |
||
206 | * Initializes the criteria object based on the given parameter |
||
207 | * |
||
208 | * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object |
||
209 | * @param array $params List of criteria data with condition, sorting and paging |
||
210 | * @return \Aimeos\MW\Criteria\Iface Initialized criteria object |
||
211 | */ |
||
212 | protected function initCriteria( \Aimeos\MW\Criteria\Iface $criteria, array $params ) |
||
220 | |||
221 | |||
222 | /** |
||
223 | * Initializes the criteria object with conditions based on the given parameter |
||
224 | * |
||
225 | * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object |
||
226 | * @param array $params List of criteria data with condition, sorting and paging |
||
227 | */ |
||
228 | protected function initCriteriaConditions( \Aimeos\MW\Criteria\Iface $criteria, array $params ) |
||
240 | |||
241 | |||
242 | /** |
||
243 | * Initializes the criteria object with the slice based on the given parameter. |
||
244 | * |
||
245 | * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object |
||
246 | * @param array $params List of criteria data with condition, sorting and paging |
||
247 | */ |
||
248 | protected function initCriteriaSlice( \Aimeos\MW\Criteria\Iface $criteria, array $params ) |
||
255 | |||
256 | |||
257 | /** |
||
258 | * Initializes the criteria object with sortations based on the given parameter |
||
259 | * |
||
260 | * @param \Aimeos\MW\Criteria\Iface $criteria Criteria object |
||
261 | * @param array $params List of criteria data with condition, sorting and paging |
||
262 | */ |
||
263 | protected function initCriteriaSortations( \Aimeos\MW\Criteria\Iface $criteria, array $params ) |
||
282 | |||
283 | |||
284 | /** |
||
285 | * Creates of updates several items at once |
||
286 | * |
||
287 | * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items |
||
288 | * @param \stdClass $request Object with request body data |
||
289 | * @return array List of items |
||
290 | */ |
||
291 | protected function saveData( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $request ) |
||
304 | |||
305 | |||
306 | /** |
||
307 | * Saves and returns the new or updated item |
||
308 | * |
||
309 | * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items |
||
310 | * @param \stdClass $entry Object including "id" and "attributes" elements |
||
311 | * @return \Aimeos\MShop\Common\Item\Iface New or updated item |
||
312 | */ |
||
313 | protected function saveEntry( \Aimeos\MShop\Common\Manager\Iface $manager, \stdClass $entry ) |
||
330 | |||
331 | |||
332 | /** |
||
333 | * Saves the item references associated via the list |
||
334 | * |
||
335 | * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager responsible for the items |
||
336 | * @param \Aimeos\MShop\Common\Item\Iface $item Domain item with an unique ID set |
||
337 | * @param \stdClass $relationships Object including the <domain>/data/attributes structure |
||
338 | */ |
||
339 | protected function saveRelationships( \Aimeos\MShop\Common\Manager\Iface $manager, |
||
365 | |||
366 | |||
367 | /** |
||
368 | * Adds the data from the given object to the item |
||
369 | * |
||
370 | * @param \Aimeos\MShop\Common\Manager\Iface $manager Manager object |
||
371 | * @param \Aimeos\MShop\Common\Item\Iface $item Item object to add the data to |
||
372 | * @param \stdClass $data Object with "attributes" property |
||
373 | * @param string $domain Domain of the type item |
||
374 | * @return \Aimeos\MShop\Common\Item\Iface Item including the data |
||
375 | */ |
||
376 | protected function addItemData(\Aimeos\MShop\Common\Manager\Iface $manager, |
||
395 | } |
||
396 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: