@mockuser

Какие существуют варианты реализации принципа открытости/закрытости в PHP?

Добрый день, хотелось бы глубже понять принцип открытости/закрытости (2 буковка SOLID). Он гласит, что программные сущности должны быть открыты для расширения но закрыты для изменений. Хотелось бы понять, какие существуют варианты расширения программной сущности, и что именно подразумевается под расширением?

По поводу "закрыты для изменений" - понятно, мы спроектировали некоторую сущность, которую, вероятно, начали использовать в своём коде другие разработчики проекта, и изменение API нашей сущности может сломать приложение во всех местах, где идут вызовы её методов.

А что с расширением? Само слово "расширение" интуитивно воспринимается как добавление публичных методов, но ведь подразумевается расширение возможностей поведения уже существующих, верно? Как это достигается? Самое банальное - наследование (реализация), в наследнике мы можем переопределить методы (поведение), сохранив при этом публичный интерфейс класса. Второе что мне представляется - делегирование, мы можем использовать композицию, и делегировать выполнение тех или иных действий объекту, внедрённому как зависимость в наш класс, при этом так-же сохранится публичный интерфейс.

Есть ли ещё какие-либо способы и вообще, правильно ли я понимаю данный принцип, а то может быть напридумывал себе чёрти-чего?

UPD: и ещё вопрос по поводу изменения, под изменением стоит понимать изменение того, как называется метод, какие параметры принимает и что возвращает, так ведь? Т.е. маркером изменения будет являться упавший тест? Просто изменение тоже интуитивно понимается как любое редактирование тела метода, даже если сигнатура и возвращаемый тип не изменились, но что-то мне подсказывает что это изменение файла на диске, а не изменение концепции сущности (которое и подразумевается в принципе открытости/закрытости).
  • Вопрос задан
  • 628 просмотров
Решения вопроса 2
@paldraken
Этом принцип предлагает спроектировать код так, чтобы добавление функционала не приводило к изменениям в существующем коде.
Расширение - стоит понимать как добавление нового функционала в программу, раньше программа так не умела - теперь умеет.
Под изменением, понимается любое внесение изменений в работающий код, при добавлении нового функционала.
В общем виде это похоже на систему плагинов. Когда добавив плагин, например в far, мы расширили его функциональность, при этом в самой программе не изменилось не строчки чтобы этот плагин заработал.

Пример на php. Например в программе есть модели Машинки и Самолета, которые надо перемещать.
Реализация прямая

class Car
{
    public function drive(){}
}

class Airplane
{
    public function fly() {};
}

class Dispatcher
{
    public function process($model) {
        if ($model instanceof Car) {
            $model->drive();
        }
        if ($model instanceof Airplane) {
            $model->fly();
        }
    }
}


Для того чтобы добавить новый функционал Пароход надо будет добавлять больше if'оф или case операторов, а так же помнить какой метод заставляет его двигаться.
Новая реализация

interface Model {
    public function move();
}

class Car implements Model
{
    public function move(){}
}

class Airplane implements Model
{
    public function move() {};
}

class Dispatcher
{
    public function process(Model $model) {
        $model->move();
    }
}


Теперь добавить новые виды моделек можно не изменяя уже существующий код.
Ответ написан
Adamos
@Adamos
Что-то вы мудрите и путаете уровень логики приложения (API) с логикой классов (к которым применимы принципы SOLID).
Банальнейший и распространеннейший пример - класс работы с БД.
Базовый класс открыт для прописывания в наследниках работы с любой БД, но сама работа с БД скрыта от вызывающего ее кода.
Так достигается главное, для чего это нужно - вызывающий код никак не завязан на какую бы то ни было внутреннюю логику работы с БД.
О.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
BorLaze
@BorLaze
Java developer
Вопрос по поводу буковки O напрямую связан со следующей буковкой L.

На пальцах - вот есть у тебя класс User. А тебе нужен Admin, который, в принципе, тоже юзер, но суперюзер.

Не надо править код User-а, чтобы добавить какой-то функционал. Надо его расширять. Но расширять так, чтобы метод типа sendMailTo(User u) работал правильно и в случае sendMailTo(u) и в случае sendMailTo(a). И тому подобное.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы