SOLID – Zasada otwarte – zamknięte

Artykuł jest aktualny

Dbam o aktualność moich najpopularniejszych artykułów, abyś otrzymał/a najwyższej jakości wiedzę.
~ 2020

Zasada otwarte – zamknięte jest drugą zasadą mnemoniku SOLID W kolejnej części cyklu o mnemoniku SOLID przyszła kolej na OCP – Zasada otwarte – zamknięte. Co dokładnie ona oznacza?

S Zasada pojedynczej odpowiedzialności (Single Responsibility Principle – SRP)
O – Zasada otwarte – zamknięte – (Open-Closed Principle – OCP)
LZasada podstawiania Liskov  – (Liskov Substitution Principle – LSP)
Zasada segregacji interfejsu – (Interface Segregation Principle – ISP)
D – Zasada odwracania zależności – (Dependency Inversion  Principle DIP)

Zasada otwarte – zamknięte

W programowaniu pewnikiem są zmiany. Zmiany są nieodłącznym aspektem podczas rozwijania projektu. Nie jesteśmy w stanie w 100% zabezpieczyć naszego kodu przed nimi, aczkolwiek istnieje reguła, która nam w tym pomoże. Jest nią właśnie zasada otwarte – zamknięte. Mówi ona tyle, że nasz kod powinien być tak skonstruowany tak, aby był zamknięty na edycję, ale był otwarty na rozszerzenia. Na pierwszy rzut oka wydaję się, że jest tu jakaś nieścisłość. Jak mamy rozwijać i zmieniać zachowanie już istniejących modułów bez ich edycji? 

Jest to możliwe, a odpowiedzią na to pytanie jest programowanie obiektowe a dokładniej abstrakcja. Spójrzmy poniżej:

public static class AreaCalculator
{
    public static double CalculateRectanglesAreas (Rectangle[] rectangles)
    {
        double area = 0;
        foreach (var rectangle in rectangles)
            area += rectangle.Height * rectangle.Width;
        return area;
    }
    public static double CalculateTrianglesAreas (Triangle[] triangles)
    {
        double area = 0;
        foreach (var triangle in triangles)
            area += (triangle.Base * triangle.Height) / 2;
        return area;
    }
}

Mamy tu dwie metody przeznaczone do obliczania sumy pól figur przekazanych jako parametr. Oddzielna istnieje dla trójkątów i oddzielna dla prostokątów. Kiedy zechcemy dodać kolejną figurę, będziemy musieli zmodyfikować klasę i dodać kolejną metodę. Łamiemy przy tym ważną zasadę wytwarzania oprogramowania o nazwie DRY (Don’t Repeat Yourself – Nie powtarzaj się), ponieważ metody te robią w zasadzie to samo, a są rozbite ze względu na typ parametru.

Refaktoryzacja

Czy nie byłoby wspaniale mieć tylko jedną funkcję do obliczania sumy pól danej figury i być zamkniętym na dodawanie kolejnej metody po dodaniu nowej figury do systemu? Utwórzmy metodę uniwersalną  taką, która jako swój parametr przyjmie abstrakcyjny byt o nazwie Shape.  Wtedy jedną funkcją moglibyśmy „załatwić” problem dodania obliczania pól dla nowych figur, które pojawiłyby się w systemie w przyszłości. Jak tego dokonać?

Zacznijmy od utworzenia abstrakcyjnej klasy bazowej o nazwie Shape.

public abstract class Shape
{
    public abstract double CalculateArea ();
}

Warto zaznaczyć, że równoważnym rozwiązaniem byłoby utworzenie interfejsu.
Następnie utwórzmy klasę Rectangle.

public class Rectangle : Shape
{
    public double Height { get; set; }
    public double Width { get; set; }
    
    public override double CalculateArea ()
    {
        return Width * Height;
    }
}

Dodałem klasę AreaCalculator, a do jej wnętrza przeniosłem zmodyfikowaną metodę CalculateArea.

public static class AreaCalculator
{
    public double CalculateArea (Shape[] shapes)
    {
        double area = 0;

        foreach (var shape in shapes)
            area += shape.CalculateArea ();
        return area;
    }
}

Teraz gdy przekażemy do tej metody jako parametr tablicę obiektów Rectangle czy Triangle metoda będzie zwracać poprawne wyniki w zależności od rodzaju przekazanej figury. A to wszystko dzięki polimorfizmowi. Teraz gdy przyjdzie nam dodać nową figurę, nie będziemy musieli dodawać nowej metody, która będzie przyjmować ten nowy kształt. Wystarczy, że przy tworzeniu nowej figury użyjemy dziedziczenia i przysłonimy odpowiednią metodę.

Nasza klasa została zamknięta na modyfikacje, a w naszym systemie została dodana możliwość obliczania pól dla nowych figur bez edycji już istniejącego kodu.

Newsletter

Zapisz się do mojego newslettera, aby nie przegapić nowych postów.

Dodatkowo wyślę Ci darmowego ebooka mojego autorstwa zawierającego mnóstwo wskazówek dla programisty aplikacji mobilnych.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Wypełnij to pole
Wypełnij to pole
Proszę wprowadzić prawidłowy adres email.
You need to agree with the terms to proceed

Menu