Принцип открытости/закрытости

Давайте рассмотрим второй принцип SOLID — открытости/закрытости. Перевод статьи на эту тему опубликовал сайт webdevblog.ru.

Photo by Jon Sailer on Unsplash

Принцип открытости/закрытости:

“Программные объекты (классы, модули, функции и т. д.) должны быть открыты для расширения, но закрыты для модификации”

Что это значит? Как можно быть открытым и закрытым программным объектом одновременно!

Давайте начнем рассмотрение, используя реальный сценарий, чтобы проиллюстрировать проблему, а затем перейдем к решению и техническим деталям.

class PhotoViewer{
    void openPhoto(){
        System.out.println("Open JPEG photo!");  
    }
}

Допустим вы написали свой класс для просмотра фотографий PhotoViewer и совершенно уверены, что он должен открывать только фотографии в формате JPEG. Позже вы поняли, что ваши пользователи постоянно пытаются просматривать PNG-фотографии. А поскольку ваше приложение не поддерживает, возникает ошибка. Итак, вы решили отредактировать исходный код, чтобы он стал поддерживать PNG.

class PhotoViewer{  
    void openPhoto(String type){
        if(type == "JPEG"){      
            System.out.println("Open JPEG photo!");
        }    
        else if(type == "PNG"){
            System.out.println("Open PNG photo!");    
        }
        else{
            System.out.println("Photo type is not supported!");
        }
    }
}

Теперь, каковы проблемы вашего кода после внесения изменений?

Что, если вы решили добавить еще один тип? Что на 100% произойдет сейчас или тогда?

В этот момент вы должны добавить еще один оператор else if. Добавление нового типа за другим делает функцию openPhoto слишком большой. А поскольку все типы существуют в одном месте, удаление некоторых строк кода из одного типа может привести к сбою других.

Таким образом, код открыт для расширения, что означает, что вы можете расширить его другими функциями. Но не закрыт для модификации, потому что каждый раз, когда вы добавляете тип, вы изменяете строки кода функции openPhoto. Многие изменения в одном и том же блоке кода по разным причинам указывают на плохой дизайн.

Хорошо, как нам разделить JPEG и PNG на разные функции в классе просмотра фотографий? Ну например так:

class PhotoViewer{  
    void openJpegPhoto(){    
        System.out.println("Open JPEG photo!");
    }
    void openPngPhoto(){
        System.out.println("Open PNG photo!");
    }
}

Теперь ваш код открыт для расширения. Вы можете легко добавлять новые типы, добавляя новые функции. Но та же проблема все еще существует. Решение не закрыто на 100% для модификации, так как изменения коснутся всех строк кода класса. Также обратите внимание, что добавление другого типа к классу PhotoViewer сделает его больше и возложит на него больше обязанностей. Это нарушает принцип единой ответственности.

Решение заключается в использовании функций объектно-ориентированного программирования с использованием универсального интерфейса для представления универсального типа фотографии, который может реализовать любой новый тип.

interface Photo{
    void open();
}

class PhotoJpeg implements Photo{  
    void open(){    
        System.out.println("Open JPEG photo!");  
    }
}

class PhotoPng implements Photo{
    void open(){    
        System.out.println("Open PNG photo!");  
    }
}

class PhotoViewer(){  
    void openPhoto(Photo photo){    
        photo.open();  
    }
}

Как видите, добавление нового типа не изменит ни одной строчки исходного кода. Вам нужно только реализовать интерфейс фотографий с новым типом и отправить фотографию в программу просмотра фотографий.

class PhotoGif implements Photo{  
    void open(){    
        System.out.println("Open GIF photo!");  
    }
}

Решение на 100% открыто для расширения и закрыто для модификации. Обратите внимание, что также применяется принцип единой ответственности.

Теперь вы знаете, что Open-Closed означает, что ваш код открыт для расширения новыми функциями и закрыт с точки зрения изменения исходного кода.

[customscript]techrocks_custom_after_post_html[/customscript]

[customscript]techrocks_custom_script[/customscript]

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх