Применение принципа открытого / закрытого в Java
Я пытаюсь понять принципы SOLID и поэтому реализовал некоторые фрагменты Java. На данный момент меня беспокоит OCP. Имея следующие образцы,
public abstract class Bakery
{
public abstract Bakegood bake();
}
/******************************************/
public class BreadBakery extends Bakery {
@Override
public Bakegood bake() {
return new Bread();
}
}
/******************************************/
public class CakeBakery extends Bakery {
@Override
public Bakegood bake() {
return new Cake();
}
}
/******************************************/
Как я могу создать правильную пекарню. Предположим, что клиент приходит в пекарню и говорит: "У меня есть два торта, пожалуйста!", Как я могу создать экземпляр CakeBakery. Конечно, я могу создать абстрактную фабрику, например:
public static Bakery createBakery(final String orderedBakegood)
{
switch(bakegood)
{
case "Cake": return new CakeBakery();
case "Bread": return new BreadBakery();
default: throw new InvalidBakeryException();
}
}
Но я не хочу использовать switch или if. Есть ли другая возможность, или я совершенно не прав с пониманием?
2 ответа
Открытый / закрытый принцип гласит:
Программные объекты (классы, модули, функции и т. Д.) Должны быть открыты для расширения, но закрыты для модификации.
Поэтому, когда вы вводите новую пекарню, вам не следует изменять существующий код. Вы можете использовать что-то вроде реестра для своих классов хлебобулочных. Если вам нужно добавить новый Bakery, просто расширьте класс Bakery и зарегистрируйте его (например, при запуске). Следовательно, модификация "if" или "switch" не требуется. Кроме того, добавление новой пекарни не требует изменения внутренних частей реестра или кода, который вызывает реестр.
Кроме того, этот метод не зависит от того, как вы регистрируете свои компоненты. Вы можете сделать это программно, с помощью файла конфигурации (xml, ...), путем сканирования пути к классам,...
Вы можете увидеть этот подход в среде Spring. По сути, среда Spring является отличным источником многих принципов проектирования.
Здесь вы можете увидеть очень простую реализацию реестра.
public class BakeryRegistry {
private Map<String, Bakery> mapping = new HashMap<>();
public BakeryRegistry() {
loadDefaultMappingFromConfigFile();
}
public Bakery getBakery(String name) {
return mapping.get(name);
}
public void registerBakery(String name, Bakery bakery) {
mapping.put(name, bakery);
}
private void loadDefaultMappingFromConfigFile() {
...
}
}
Может быть, статья Killing Switch Заявления с реестром может помочь. Он основан на JavaScript, но принцип тот же.
Придуманная абстракция вызывает проблему здесь. Клиенты не будут спрашивать пекарню об абстрактных "выпечках", потому что вся выпечка не подлежит замене. Хлеб не заменяет торт, и наоборот. Объединение этих двух разных продуктов в одну иерархию наследования является нарушением принципа подстановки Лискова.
Принципы SOLID взаимосвязаны, поэтому применение OCP будет затруднено или невозможно без применения LSP. См. Введение в LSP, где Роберт Мартин описывает наследование как критически важное для OCP и далее описывает LSP как критическое для наследования.