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 Version 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 Version, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 31 | final class Version extends Object implements IEquatable, IComparable |
||
| 32 | { |
||
| 33 | |||
| 34 | /** |
||
| 35 | * Crea una nueva instancia con los números principal, secundario, de |
||
| 36 | * compilación (opcional) y revisión (opcional). |
||
| 37 | * Para comprobar si la versión es válida, usar el método isValid. |
||
| 38 | * |
||
| 39 | * @param int $major Componente principal |
||
| 40 | * @param int $minor Componente secundario |
||
| 41 | * @param int|string|VersionComponent|null $build Componente de compilación |
||
| 42 | * @param int|string|VersionComponent|null $revision Componente de revisión |
||
| 43 | * |
||
| 44 | * @throws InvalidArgumentException |
||
| 45 | * */ |
||
| 46 | 33 | public function __construct($major, $minor, $build = null, $revision = null) |
|
| 126 | |||
| 127 | /** |
||
| 128 | * Convierte una cadena a su representación del tipo Version. |
||
| 129 | * |
||
| 130 | * @param Version|string|int|float|array $value Objeto a convertir. |
||
| 131 | * |
||
| 132 | * @return Version Objeto convertido desde $value. |
||
| 133 | * */ |
||
| 134 | 26 | public static function parse($value) |
|
| 185 | |||
| 186 | /** |
||
| 187 | * Obtiene el valor del componente principal del número de versión del |
||
| 188 | * objeto actual. |
||
| 189 | * Esta propiedad es de sólo lectura. |
||
| 190 | * |
||
| 191 | * @var int Componente principal del número de versión. |
||
| 192 | * */ |
||
| 193 | public $Major; |
||
| 194 | private $major; |
||
| 195 | |||
| 196 | /** |
||
| 197 | * Getter for Major property. |
||
| 198 | * |
||
| 199 | * @return integer |
||
| 200 | * @see Version::Major. |
||
| 201 | */ |
||
| 202 | 57 | public function getMajor() |
|
| 206 | |||
| 207 | |||
| 208 | /** |
||
| 209 | * Obtiene el valor del componente secundario del número de versión del |
||
| 210 | * objeto actual. |
||
| 211 | * Esta propiedad es de sólo lectura. |
||
| 212 | * |
||
| 213 | * @var int Componente secundario del número de versión. |
||
| 214 | * */ |
||
| 215 | public $Minor; |
||
| 216 | private $minor; |
||
| 217 | |||
| 218 | /** |
||
| 219 | * Getter for minor property. |
||
| 220 | * |
||
| 221 | * @return integer |
||
| 222 | * @see Version::Minor. |
||
| 223 | */ |
||
| 224 | 35 | public function getMinor() |
|
| 228 | |||
| 229 | /** |
||
| 230 | * Obtiene el valor del componente de compilación del número de versión |
||
| 231 | * del objeto actual. |
||
| 232 | * Esta propiedad es de sólo lectura. |
||
| 233 | * |
||
| 234 | * @var VersionComponent Componente de compilación del número de versión. |
||
| 235 | * */ |
||
| 236 | public $Build; |
||
| 237 | private $build; |
||
| 238 | |||
| 239 | /** |
||
| 240 | * Getter for Build property. |
||
| 241 | * |
||
| 242 | * @return VersionComponent |
||
| 243 | * @see Version::Build |
||
| 244 | */ |
||
| 245 | 47 | public function getBuild() |
|
| 249 | |||
| 250 | /** |
||
| 251 | * Obtiene el valor del componente de revisión del número de versión del |
||
| 252 | * objeto actual. |
||
| 253 | * Esta propiedad es de sólo lectura. |
||
| 254 | * |
||
| 255 | * @var VersionComponent Componente de revisión del número de versión. |
||
| 256 | * */ |
||
| 257 | public $Revision; |
||
| 258 | private $revision; |
||
| 259 | |||
| 260 | /** |
||
| 261 | * Getter for Revision property. |
||
| 262 | * |
||
| 263 | * @return VersionComponent |
||
| 264 | * @see Version::Revision |
||
| 265 | */ |
||
| 266 | 42 | public function getRevision() |
|
| 270 | |||
| 271 | |||
| 272 | /** |
||
| 273 | * Convierte la instancia actual en su representación en cadena. |
||
| 274 | * Por defecto, si no están definidos los componentes de compilación y |
||
| 275 | * revisión, no se incluyen en la salida. |
||
| 276 | * Use el método isValid si quiere determinar si la versión es válida |
||
| 277 | * antes de devolver esta cadena. |
||
| 278 | * |
||
| 279 | * @return string Representación de la versión en forma de cadena: |
||
| 280 | * 'major.minor[.build[.revision]]' |
||
| 281 | * @see VersionComponent::isNull |
||
| 282 | * @see Version::isValid |
||
| 283 | * */ |
||
| 284 | 17 | public function toString() |
|
| 285 | { |
||
| 286 | 16 | $s[0] = $this->Major; |
|
| 287 | 16 | $s[1] = $this->Minor; |
|
| 288 | |||
| 289 | 16 | if ($this->Revision->IsNotNull()) { |
|
| 290 | 6 | $s[2] = $this->Build; |
|
| 291 | 6 | $s[3] = $this->Revision; |
|
| 292 | 6 | } else { |
|
| 293 | 10 | if ($this->Build->IsNotNull()) { |
|
| 294 | 6 | $s[2] = $this->Build; |
|
| 295 | 6 | } |
|
| 296 | 17 | } |
|
| 297 | 16 | $v = implode('.', $s); |
|
| 298 | |||
| 299 | 16 | return $v; |
|
| 300 | } |
||
| 301 | |||
| 302 | /** |
||
| 303 | * Indica si la instancia actual es un número de versión válido. |
||
| 304 | * |
||
| 305 | * Se considera válido si: |
||
| 306 | * 1. Major o Minor es mayor a cero (0). No puede ser '0.0'. |
||
| 307 | * 2. Build y Revision son nulos (no están definidos). |
||
| 308 | * 3. Build está definido pero Revision no. |
||
| 309 | * 4. Ambos están definidos, pero no poseen la parte de la cadena. |
||
| 310 | * 5. Ambos están definidos, pero Build no posee la parte de cadena. |
||
| 311 | * 6. Build está definido y tiene la cadena, pero Revision no está definido. |
||
| 312 | * 7. Revision posee cadena, pero Build no. |
||
| 313 | * |
||
| 314 | * @return boolean Un valor que indica si la instancia actual es válida. |
||
| 315 | * */ |
||
| 316 | 16 | public function isValid() |
|
| 353 | |||
| 354 | /** |
||
| 355 | * Determina si el objeto $other especificado es igual a la instancia actual. |
||
| 356 | * |
||
| 357 | * @param Version $other El otro objeto a comparar. |
||
| 358 | * |
||
| 359 | * @return bool `true` si $other es igual esta instancia; caso contrario, |
||
| 360 | * `false`. |
||
| 361 | * */ |
||
| 362 | 32 | public function equals($other) |
|
| 376 | |||
| 377 | |||
| 378 | #region IComparable |
||
| 379 | |||
| 380 | /** |
||
| 381 | * Determina la posición relativa de esta instancia con respecto al objeto especificado. |
||
| 382 | * |
||
| 383 | * For types different than ``Version``: |
||
| 384 | * - ``integer`` and ``null`` are always < 0; |
||
| 385 | * - ``string`` and ``array`` are parsed and then evaluated (if is not parseable, always > 0); |
||
| 386 | * - other types are always > 0 |
||
| 387 | * |
||
| 388 | * @param Version|int|string|mixed $other |
||
| 389 | * The other object to compare with. |
||
| 390 | * |
||
| 391 | * @return integer|null |
||
| 392 | * Returns: |
||
| 393 | * - ``= 0`` if this instance is considered equivalent to $other; |
||
| 394 | * - ``> 0`` si esta instancia se considera mayor a $other; |
||
| 395 | * - ``< 0`` si esta instancia se considera menor a $other. |
||
| 396 | * - ``null`` if this instance can't be compared against $other . |
||
| 397 | * @see Object::compare() |
||
| 398 | * */ |
||
| 399 | 24 | public function compareTo($other) |
|
| 451 | |||
| 452 | #endregion |
||
| 453 | } |
||
| 454 |
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.