Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like HandFinder 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 HandFinder, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | class HandFinder |
||
13 | { |
||
14 | private $cardValidator; |
||
15 | |||
16 | /** |
||
17 | * Constructor |
||
18 | * |
||
19 | * @param CardValidator $cardValidator [description] |
||
20 | */ |
||
21 | public function __construct(CardValidator $cardValidator) |
||
25 | |||
26 | /** |
||
27 | * |
||
28 | * Will return the best hand with the given cards. |
||
29 | * |
||
30 | * IMPORTANT: the oder in wich the methods are called is critical. |
||
31 | * Changing it will break the code, as a Three of a Kind will always |
||
32 | * be found in a Full House for instance. |
||
33 | * |
||
34 | * @param array $cards |
||
35 | * |
||
36 | * @return string |
||
37 | */ |
||
38 | public function findHand(array $cards) |
||
77 | |||
78 | /** |
||
79 | * Sort cards |
||
80 | * |
||
81 | * @param array $cards |
||
82 | * |
||
83 | * @return array |
||
84 | */ |
||
85 | private function sortCards(array $cards) |
||
115 | |||
116 | /** |
||
117 | * Get rank of a card |
||
118 | * |
||
119 | * @param array $cards |
||
120 | * |
||
121 | * @return int |
||
122 | */ |
||
123 | private function getRank(array $cards) |
||
151 | |||
152 | /** |
||
153 | * Return a formated response. |
||
154 | * |
||
155 | * @param string $handName |
||
156 | * @param int $handRank |
||
157 | * @param int $cardRank |
||
158 | * @param array $response |
||
159 | * |
||
160 | * @return array |
||
161 | */ |
||
162 | private function getResponse($handName, $handRank, $cardRank, array $response) |
||
171 | |||
172 | private function findMultipleFaceCards(array $cards) |
||
244 | /** |
||
245 | * Return true if the cards are a Royal Flush. |
||
246 | * |
||
247 | * @param array $cards |
||
248 | * |
||
249 | * @return bool |
||
250 | */ |
||
251 | private function isRoyalFlush(array $cards) |
||
268 | |||
269 | /** |
||
270 | * Return an array if the cards are a Straight Flush |
||
271 | * otherwise return false. |
||
272 | * |
||
273 | * @param array $cards |
||
274 | * |
||
275 | * @return array|bool |
||
276 | */ |
||
277 | private function isStraightFlush(array $cards) |
||
288 | |||
289 | /** |
||
290 | * Return an array if the cards are a Four of a Kind |
||
291 | * otherwise return false. |
||
292 | * |
||
293 | * @example AC AD AS AH 2D 7D 10S |
||
294 | * |
||
295 | * @param array $cards |
||
296 | * |
||
297 | * @return array|bool |
||
298 | */ |
||
299 | View Code Duplication | private function isFourOfAKind(array $cards) |
|
311 | |||
312 | /** |
||
313 | * Return an array if the cards are a Full House |
||
314 | * otherwise return false. |
||
315 | * |
||
316 | * @param array $cards |
||
317 | * |
||
318 | * @return array|bool |
||
319 | */ |
||
320 | private function isFullHouse(array $cards) |
||
359 | |||
360 | /** |
||
361 | * Return true if the cards are a Flush. |
||
362 | * |
||
363 | * @param array $cards |
||
364 | * |
||
365 | * @return bool |
||
366 | */ |
||
367 | private function isFlush(array $cards) |
||
404 | |||
405 | /** |
||
406 | * Return false if the cards are not a Straight |
||
407 | * otherwise it returns an array. |
||
408 | * |
||
409 | * @todo Straight from bottom, i.e. AC 2D 3H 4H 5S |
||
410 | * |
||
411 | * @param array $cards |
||
412 | * |
||
413 | * @return array|bool |
||
414 | */ |
||
415 | private function isStraight(array $cards) |
||
450 | |||
451 | /** |
||
452 | * Return an array if it's a Tree of a Kind or false if not. |
||
453 | * |
||
454 | * @param array $cards |
||
455 | * |
||
456 | * @return array|bool |
||
457 | */ |
||
458 | View Code Duplication | private function isTreeOfAKind(array $cards) |
|
470 | |||
471 | /** |
||
472 | * Find one or n pair |
||
473 | * |
||
474 | * @param string $typeOfPair |
||
475 | * @param int $nbCards |
||
476 | * @param array $cards |
||
477 | * |
||
478 | * @return array|bool |
||
479 | */ |
||
480 | private function findPair($typeOfPair, $handRank, $nbCards, array $cards) |
||
499 | |||
500 | /** |
||
501 | * Return an array if it's Two Pairs or false if not. |
||
502 | * |
||
503 | * @param array $cards |
||
504 | * |
||
505 | * @return array|bool |
||
506 | */ |
||
507 | private function isTwoPairs(array $cards) |
||
515 | |||
516 | /** |
||
517 | * Return an array if it's One Pair or false if not. |
||
518 | * |
||
519 | * @param array $cards |
||
520 | * |
||
521 | * @return array|bool |
||
522 | */ |
||
523 | private function isOnePair(array $cards) |
||
531 | |||
532 | /** |
||
533 | * Return an array if it's High Card or false if not. |
||
534 | * |
||
535 | * @param array $cards |
||
536 | * |
||
537 | * @return array|bool |
||
538 | */ |
||
539 | private function isHighCard(array $cards) |
||
546 | } |
||
547 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.