Имеет ли смысл принцип "Открыто для расширения, закрыто для модификации"?
Мне кажется, что Бобу Мартину нужно что-то, начиная с O, чтобы сделать SOLID, и он нашел в какой-то старой книге этот (возможно, бесполезный) принцип Open/Closed.
Как Open/Closed может сосуществовать с Single Responsibility, в котором говорится, что у класса должна быть одна причина для изменения?
Если я хочу следовать Open/Closed в долгоживущей системе, должен ли я иметь цепочку из десятков / сотен классов, каждый из которых расширяет предыдущий?
3 ответа
Принцип "открыто / закрыто" подразумевает, что вы можете создавать системы, в которые добавляются новые функции, добавляя новый код, а не изменяя старый код. Чтобы полностью соответствовать принципу открытого / закрытого, нужно иметь совершенное предвидение. Ибо для того, чтобы создать систему, которая полностью открыта для расширения и закрыта для всех модификаций, нужно уметь точно предсказывать будущее. Необходимо заранее знать, какие новые функции потребует клиент, чтобы добавить в код точки расширения.
Сказав, что мы могли бы разработать системы, которые достаточно хорошо соответствуют принципу открытого / закрытого. Используя итеративный процесс с большим количеством обратной связи и рефакторинга, мы можем улучшить части системы, которые чаще всего меняются, делая их открытыми для расширения и закрытыми для модификации.
Как сказал Боб Мартин в одной из своих лекций: "Мы не можем полностью соответствовать принципу открытого / закрытого. Это не значит, что мы должны просто полностью отказаться от принципа открытого / закрытого. Может быть трудно заставить целые системы соответствовать принципу открытого / закрытого, но нетрудно заставить функции или классы или меньшие компоненты соответствовать принципу открытого / закрытого
Я также пришел сюда, задаваясь вопросом о всей части «Закрыто для модификации», но я пришел к выводу, который, как мне кажется, лучше всего продемонстрировать на примере:
public class FixedSizeCache {
private int maxCacheSize = 8192;
public FixedSizeCache() {
// ...
}
// ...
}
Приведенный выше пример не нарушает принцип единой ответственности, но нарушает принцип открытости/закрытости довольно очевидным образом: всякий раз, когда вам нужен FixedSizeCache другого фиксированного размера, вам нужно будет изменить исходный код класса.
Другими словами, мы должны стремиться писать код, который не нарушает принцип открытости/закрытости очевидным образом, но это не означает, что нам нужно писать код, который полностью заперт в камне и никогда не будет изменен (поскольку бизнес-требования меняются и это должно быть отражено в нашем коде).
Но если одно и то же бизнес-требование меняется 7 раз и вам нужно изменить свой код 7 раз, вы, вероятно, нарушаете принцип открытости/закрытости и должны провести рефакторинг.
Красиво сформулированный вопрос!
Если я хочу следовать Open/Closed в долгоживущей системе, должен ли я иметь цепочку из десятков / сотен классов, каждый из которых расширяет предыдущий?
Это как раз то, что я наблюдал некоторое время назад на "долгоживущей системе"; десятки классов, незначительно расширяющих суперклассы. С другой стороны, современная конструкция python идет в точности против этого принципа, и у меня было ощущение, что нарушение Open/Closed современного python было основной причиной полезности и простоты многих библиотек python. Итак, я проверил ТАК и нашел ваш вопрос. Хорошо сформулировано!