Skip to content

Latest commit

 

History

History
169 lines (124 loc) · 4.52 KB

File metadata and controls

169 lines (124 loc) · 4.52 KB

Analysis of the Poor Design in Terms of the Interface Segregation Principle (ISP)

The provided code violates the Interface Segregation Principle (ISP) from SOLID design principles. Here's an analysis of the issues:

Example Code

<?php

namespace App\Solid\ISP\Bad;

class Car implements IDrivable
{
    function GoForward(): void
    {
       echo "Car going forward. \r\n";
    }

    function GoBackward(): void
    {
        echo "Car going backward. \r\n";
    }

    function TurnLeft(): void
    {
        echo "Car going turns left. \r\n";
    }

    function TurnRight(): void
    {
        echo "Car going turns right.. \r\n";
    }
}
<?php

namespace App\Solid\ISP\Bad;

interface IDrivable
{
    function GoForward(): void;

    function GoBackward(): void;

    function TurnLeft(): void;

    function TurnRight(): void;
}
<?php

namespace App\Solid\ISP\Bad;

use Nette\NotImplementedException;

class Train implements IDrivable
{
    function GoForward(): void
    {
        echo "Train going forward. \r\n";
    }

    function GoBackward(): void
    {
        echo "Train going backward. \r\n";
    }

    function TurnLeft(): void
    {
        throw new NotImplementedException();
    }

    function TurnRight(): void
    {
        throw new NotImplementedException();
    }
}

Poor Design Analysis

  1. Violation of Interface Segregation Principle (ISP):

    • Unnecessary Implementation: The IDrivable interface requires both Car and Train classes to implement all four methods: GoForward, GoBackward, TurnLeft, and TurnRight. However, a Train typically does not make sharp turns like a car does. The TurnLeft and TurnRight methods are not applicable to trains, resulting in a forced implementation of methods that do not make sense for all implementing classes.
    • Code Smell: The Train class has to provide default (or placeholder) implementations for TurnLeft and TurnRight that throw exceptions. This is a sign that the interface is not properly segmented according to the needs of the implementing classes.
  2. Lack of Flexibility:

    • Overly General Interface: A single, all-encompassing interface (IDrivable) imposes unnecessary requirements on classes. It forces classes to implement methods that may not be relevant to their specific functionality, reducing flexibility and increasing the likelihood of runtime errors.

Improved Design

To adhere to the Interface Segregation Principle, you should create more specific interfaces that are tailored to the different capabilities of the classes. Here’s a refactored design:

  1. Define Separate Interfaces:

    <?php
    
    namespace App\Solid\ISP\Good;
    
    interface IMovable
    {
        function GoForward(): void;
    
        function GoBackward(): void;
    }
    
    interface ITurnable
    {
        function TurnLeft(): void;
    
        function TurnRight(): void;
    }
  2. Implement Specific Interfaces in Classes:

    <?php
    
    namespace App\Solid\ISP\Good;
    
    class Car implements IMovable, ITurnable
    {
        function GoForward(): void
        {
            echo "Car going forward. \r\n";
        }
    
        function GoBackward(): void
        {
            echo "Car going backward. \r\n";
        }
    
        function TurnLeft(): void
        {
            echo "Car turning left. \r\n";
        }
    
        function TurnRight(): void
        {
            echo "Car turning right. \r\n";
        }
    }
    <?php
    
    namespace App\Solid\ISP\Good;
    
    class Train implements IMovable
    {
        function GoForward(): void
        {
            echo "Train going forward. \r\n";
        }
    
        function GoBackward(): void
        {
            echo "Train going backward. \r\n";
        }
    }

Improved Design Benefits

  • Adherence to ISP: Each class now only implements the methods that are relevant to it, adhering to the Interface Segregation Principle. Car implements both IMovable and ITurnable, while Train only implements IMovable.
  • Increased Flexibility: This design allows for more flexibility in adding new types of vehicles that may need different sets of functionalities without impacting existing code.
  • Better Maintainability: The code becomes easier to maintain and understand because each interface and class has a clear responsibility and does not contain unnecessary methods.

By splitting the interface into smaller, more specific ones, you ensure that classes are not burdened with methods that are not relevant to them, leading to a more maintainable and extensible design.