2

我尝试理解 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 语句。还有其他可能性还是我的理解完全错误?

4

2 回答 2

3

开闭原则说:

软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。

因此,无论何时引入新的 Bakery,都不应修改现有代码。您可以为 Bakery 课程使用注册表之类的东西。如果您需要添加一个新的 Bakery,只需扩展 Bakery 类并注册它(例如在启动时)。因此不需要“if”或“switch”修改。此外,添加新的 Bakery 不需要更改注册表的内部结构或调用注册表的代码。

此外,此技术不依赖于您注册组件的方式。您可以通过类路径扫描,使用配置文件(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 Statements With A Registry可以提供帮助。它基于 JavaScript,但原理是一样的。

于 2016-03-15T09:18:21.450 回答
0

人为的抽象在这里引起了问题。顾客不会向面包店索要抽象的“烘焙食品”,因为所有烘焙食品都不可替代。面包不能代替蛋糕,反之亦然。将这两种不同的产品包装到一个继承层次结构中违反了 Liskov 替换原则。

SOLID 原则是相互关联的,因此如果不先应用 LSP,将很难或不可能应用 OCP。请参阅LSP 简介,其中 Robert Martin 将继承描述为对 OCP 至关重要,并继续将 LSP 描述为对继承至关重要。

于 2016-03-15T16:27:59.263 回答