Complex classes like Packer 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 Packer, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 19 | class Packer implements LoggerAwareInterface |
||
| 20 | { |
||
| 21 | use LoggerAwareTrait; |
||
| 22 | |||
| 23 | /** |
||
| 24 | * List of items to be packed |
||
| 25 | * @var ItemList |
||
| 26 | */ |
||
| 27 | protected $items; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * List of box sizes available to pack items into |
||
| 31 | * @var BoxList |
||
| 32 | */ |
||
| 33 | protected $boxes; |
||
| 34 | |||
| 35 | /** |
||
| 36 | * Constructor |
||
| 37 | */ |
||
| 38 | 24 | public function __construct() |
|
| 45 | |||
| 46 | /** |
||
| 47 | * Add item to be packed |
||
| 48 | * @param Item $item |
||
| 49 | * @param int $qty |
||
| 50 | */ |
||
| 51 | 14 | public function addItem(Item $item, $qty = 1) |
|
| 52 | { |
||
| 53 | 14 | for ($i = 0; $i < $qty; $i++) { |
|
| 54 | 14 | $this->items->insert($item); |
|
| 55 | 14 | } |
|
| 56 | 14 | $this->logger->log(LogLevel::INFO, "added {$qty} x {$item->getDescription()}"); |
|
| 57 | 14 | } |
|
| 58 | |||
| 59 | /** |
||
| 60 | * Set a list of items all at once |
||
| 61 | * @param \Traversable|array $items |
||
| 62 | */ |
||
| 63 | 4 | public function setItems($items) |
|
| 64 | { |
||
| 65 | 2 | if ($items instanceof ItemList) { |
|
| 66 | 4 | $this->items = clone $items; |
|
| 67 | 2 | } else { |
|
| 68 | 2 | $this->items = new ItemList(); |
|
| 69 | 2 | foreach ($items as $item) { |
|
| 70 | 2 | $this->items->insert($item); |
|
| 71 | 2 | } |
|
| 72 | } |
||
| 73 | 2 | } |
|
| 74 | |||
| 75 | /** |
||
| 76 | * Add box size |
||
| 77 | * @param Box $box |
||
| 78 | */ |
||
| 79 | 14 | public function addBox(Box $box) |
|
| 80 | { |
||
| 81 | 14 | $this->boxes->insert($box); |
|
| 82 | 14 | $this->logger->log(LogLevel::INFO, "added box {$box->getReference()}"); |
|
| 83 | 14 | } |
|
| 84 | |||
| 85 | /** |
||
| 86 | * Add a pre-prepared set of boxes all at once |
||
| 87 | * @param BoxList $boxList |
||
| 88 | */ |
||
| 89 | 2 | public function setBoxes(BoxList $boxList) |
|
| 93 | |||
| 94 | /** |
||
| 95 | * Pack items into boxes |
||
| 96 | * |
||
| 97 | * @throws \RuntimeException |
||
| 98 | * @return PackedBoxList |
||
| 99 | */ |
||
| 100 | 14 | public function pack() |
|
| 113 | |||
| 114 | /** |
||
| 115 | * Pack items into boxes using the principle of largest volume item first |
||
| 116 | * |
||
| 117 | * @throws \RuntimeException |
||
| 118 | * @return PackedBoxList |
||
| 119 | 15 | */ |
|
| 120 | public function doVolumePacking() |
||
| 171 | |||
| 172 | /** |
||
| 173 | * Pack as many items as possible into specific given box |
||
| 174 | * @param Box $box |
||
| 175 | * @param ItemList $items |
||
| 176 | * @return PackedBox packed box |
||
| 177 | 4 | */ |
|
| 178 | public function packIntoBox(Box $box, ItemList $items) |
||
| 256 | |||
| 257 | 4 | /** |
|
| 258 | * @param Item $item |
||
| 259 | * @param int $remainingDepth |
||
| 260 | * @param int $remainingWeight |
||
| 261 | * @return bool |
||
| 262 | */ |
||
| 263 | protected function isItemTooLargeForBox(Item $item, $remainingDepth, $remainingWeight) { |
||
| 266 | |||
| 267 | 23 | /** |
|
| 268 | * Figure out space left for next item if we pack this one in it's regular orientation |
||
| 269 | 23 | * @param Item $item |
|
| 270 | * @param int $remainingWidth |
||
| 271 | 23 | * @param int $remainingLength |
|
| 272 | 23 | * @return int |
|
| 273 | 23 | */ |
|
| 274 | 23 | protected function fitsSameGap(Item $item, $remainingWidth, $remainingLength) { |
|
| 277 | 23 | ||
| 278 | 23 | /** |
|
| 279 | * Figure out space left for next item if we pack this one rotated by 90deg |
||
| 280 | 23 | * @param Item $item |
|
| 281 | * @param int $remainingWidth |
||
| 282 | * @param int $remainingLength |
||
| 283 | 23 | * @return int |
|
| 284 | 8 | */ |
|
| 285 | 8 | protected function fitsRotatedGap(Item $item, $remainingWidth, $remainingLength) { |
|
| 288 | 23 | ||
| 289 | 23 | /** |
|
| 290 | 23 | * @param Item $item |
|
| 291 | * @param Item|null $nextItem |
||
| 292 | 23 | * @param $remainingWidth |
|
| 293 | 23 | * @param $remainingLength |
|
| 294 | * @return bool |
||
| 295 | 23 | */ |
|
| 296 | protected function fitsBetterRotated(Item $item, Item $nextItem = null, $remainingWidth, $remainingLength) { |
||
| 305 | 22 | ||
| 306 | 22 | /** |
|
| 307 | 8 | * Does item fit in specified gap |
|
| 308 | 8 | * @param Item $item |
|
| 309 | 8 | * @param $remainingWidth |
|
| 310 | 8 | * @param $remainingLength |
|
| 311 | * @return bool |
||
| 312 | 23 | */ |
|
| 313 | protected function fitsGap(Item $item, $remainingWidth, $remainingLength) { |
||
| 317 | 1 | ||
| 318 | 1 | /** |
|
| 319 | 1 | * Figure out if we can stack the next item vertically on top of this rather than side by side |
|
| 320 | 1 | * Used when we've packed a tall item, and have just put a shorter one next to it |
|
| 321 | 23 | * @param Item $item |
|
| 322 | 19 | * @param Item $nextItem |
|
| 323 | 19 | * @param $maxStackDepth |
|
| 324 | 19 | * @param $remainingWeight |
|
| 325 | 19 | * @return bool |
|
| 326 | 19 | */ |
|
| 327 | 19 | protected function canStackItemInLayer(Item $item, Item $nextItem, $maxStackDepth, $remainingWeight) |
|
| 334 | 17 | ||
| 335 | 17 | /** |
|
| 336 | 17 | * @param $layerWidth |
|
| 337 | * @param $layerLength |
||
| 338 | 17 | * @param $layerDepth |
|
| 339 | 17 | * @return bool |
|
| 340 | */ |
||
| 341 | 23 | protected function isLayerStarted($layerWidth, $layerLength, $layerDepth) { |
|
| 344 | } |
||
| 345 |