Complex classes like Fraction 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 Fraction, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 8 | class Fraction |
||
| 9 | { |
||
| 10 | /** @var int $whole */ |
||
| 11 | private $whole; |
||
| 12 | |||
| 13 | /** @var int $numerator */ |
||
| 14 | private $numerator; |
||
| 15 | |||
| 16 | /** @var int $denominator */ |
||
| 17 | private $denominator; |
||
| 18 | |||
| 19 | /** @var bool $negative */ |
||
| 20 | private $negative; |
||
| 21 | |||
| 22 | 8 | public function __construct($whole = 0, $numerator = 0, $denominator = 1) |
|
| 23 | { |
||
| 24 | 8 | $this->whole = $whole; |
|
| 25 | 8 | $this->numerator = $numerator; |
|
| 26 | 8 | $this->denominator = $denominator; |
|
| 27 | 8 | $this->negative = false; |
|
| 28 | 8 | } |
|
| 29 | |||
| 30 | /** |
||
| 31 | * @return int |
||
| 32 | */ |
||
| 33 | 1 | public function getWhole() |
|
| 34 | { |
||
| 35 | 1 | return $this->whole; |
|
| 36 | } |
||
| 37 | |||
| 38 | /** |
||
| 39 | * @param int $whole |
||
| 40 | * @return Fraction |
||
| 41 | */ |
||
| 42 | 6 | public function setWhole($whole) |
|
| 43 | { |
||
| 44 | 6 | $this->throwExceptionIfNegative($whole); |
|
| 45 | 5 | $this->whole = $whole; |
|
| 46 | 5 | return $this; |
|
| 47 | } |
||
| 48 | |||
| 49 | /** |
||
| 50 | * @return int |
||
| 51 | */ |
||
| 52 | 1 | public function getNumerator() |
|
| 53 | { |
||
| 54 | 1 | return $this->numerator; |
|
| 55 | } |
||
| 56 | |||
| 57 | /** |
||
| 58 | * @param int $numerator |
||
| 59 | * @return Fraction |
||
| 60 | */ |
||
| 61 | 6 | public function setNumerator($numerator) |
|
| 62 | { |
||
| 63 | 6 | $this->throwExceptionIfNegative($numerator); |
|
| 64 | 5 | $this->numerator = $numerator; |
|
| 65 | 5 | return $this; |
|
| 66 | } |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @return int |
||
| 70 | */ |
||
| 71 | 1 | public function getDenominator() |
|
| 72 | { |
||
| 73 | 1 | return $this->denominator; |
|
| 74 | } |
||
| 75 | |||
| 76 | /** |
||
| 77 | * @param int $denominator |
||
| 78 | * @return Fraction |
||
| 79 | */ |
||
| 80 | 6 | public function setDenominator($denominator) |
|
| 81 | { |
||
| 82 | 6 | $this->throwExceptionIfNegative($denominator); |
|
| 83 | 5 | $this->denominator = $denominator; |
|
| 84 | 5 | return $this; |
|
| 85 | } |
||
| 86 | |||
| 87 | 2 | private function refactor() |
|
| 88 | { |
||
| 89 | // 9/8 would become 1 1/8 for instance |
||
| 90 | 2 | if ($this->shouldRefactorWhole()) { |
|
| 91 | 2 | $this->refactorWhole(); |
|
| 92 | 2 | } |
|
| 93 | 2 | if ($this->shouldRefactorFraction()) { |
|
| 94 | 2 | $this->refactorFraction(); |
|
| 95 | 2 | } |
|
| 96 | 2 | } |
|
| 97 | |||
| 98 | /** |
||
| 99 | * @return bool |
||
| 100 | */ |
||
| 101 | 2 | private function shouldRefactorWhole() |
|
| 102 | { |
||
| 103 | 2 | return $this->numerator >= $this->denominator |
|
| 104 | 2 | && $this->denominator > 0; |
|
| 105 | } |
||
| 106 | |||
| 107 | /** |
||
| 108 | * @return bool |
||
| 109 | */ |
||
| 110 | 2 | private function shouldRefactorFraction() |
|
| 115 | |||
| 116 | 2 | private function refactorWhole() |
|
| 124 | |||
| 125 | 2 | private function refactorFraction() |
|
| 126 | { |
||
| 127 | 2 | $gcd = $this->getGreatestCommonDenominator($this->numerator, $this->denominator); |
|
| 128 | 2 | $this->numerator = $this->numerator / $gcd; |
|
| 129 | 2 | $this->denominator = $this->denominator / $gcd; |
|
| 130 | 2 | } |
|
| 131 | |||
| 132 | /** |
||
| 133 | * @param int $x |
||
| 134 | * @param int $y |
||
| 135 | * @return int |
||
| 136 | */ |
||
| 137 | 2 | private function getGreatestCommonDenominator($x, $y) |
|
| 151 | |||
| 152 | /** |
||
| 153 | * @param int $num |
||
| 154 | * @return array The common denominators of $num |
||
| 155 | */ |
||
| 156 | 2 | private function getFactors($num) |
|
| 157 | { |
||
| 158 | 2 | $factors = []; |
|
| 159 | // get factors of the numerator |
||
| 160 | 2 | for ($x = 1; $x <= $num; $x ++) { |
|
| 161 | 2 | if ($num % $x == 0) { |
|
| 162 | 2 | $factors[] = $x; |
|
| 163 | 2 | } |
|
| 164 | 2 | } |
|
| 165 | 2 | return $factors; |
|
| 166 | } |
||
| 167 | |||
| 168 | /** |
||
| 169 | * @return bool |
||
| 170 | */ |
||
| 171 | 3 | public function isNegative() |
|
| 175 | |||
| 176 | /** |
||
| 177 | * @param bool $negative |
||
| 178 | * @return Fraction |
||
| 179 | */ |
||
| 180 | 1 | public function setNegative($negative) |
|
| 185 | |||
| 186 | /** |
||
| 187 | * @return bool |
||
| 188 | */ |
||
| 189 | 1 | public function isInteger() |
|
| 193 | |||
| 194 | /** |
||
| 195 | * @return string |
||
| 196 | */ |
||
| 197 | 2 | public function __toString() |
|
| 206 | |||
| 207 | /** |
||
| 208 | * @return string |
||
| 209 | */ |
||
| 210 | 2 | private function getStringWhole() |
|
| 214 | |||
| 215 | /** |
||
| 216 | * @return string |
||
| 217 | */ |
||
| 218 | 2 | private function getStringFraction() |
|
| 222 | |||
| 223 | /** |
||
| 224 | * @param string $whole |
||
| 225 | * @param string $fraction |
||
| 226 | * @return string |
||
| 227 | */ |
||
| 228 | 2 | private function formatString($whole, $fraction) |
|
| 234 | |||
| 235 | /** |
||
| 236 | * @param $whole |
||
| 237 | * @param $fraction |
||
| 238 | * @return string |
||
| 239 | */ |
||
| 240 | 2 | private function getSpace($whole, $fraction) |
|
| 244 | |||
| 245 | /** |
||
| 246 | * @param $whole |
||
| 247 | * @param $fraction |
||
| 248 | * @return string |
||
| 249 | */ |
||
| 250 | 2 | private function getNegative() |
|
| 254 | |||
| 255 | /** |
||
| 256 | * @return float |
||
| 257 | */ |
||
| 258 | 1 | public function toDecimal() |
|
| 268 | |||
| 269 | /** |
||
| 270 | * @param $num |
||
| 271 | * @throws PhiException |
||
| 272 | */ |
||
| 273 | 8 | public function throwExceptionIfNegative($num) |
|
| 279 | } |
||
| 280 |