【问题标题】:Application of open/closed principle in JavaJava中开闭原理的应用
【发布时间】:2016-03-15 09:02:36
【问题描述】:

我尝试了解 SOLID 原理,因此实现了一些 java sn-ps。我现在关心的是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 语句。是否还有其他可能,或者我的理解完全错误?

【问题讨论】:

  • switch 或 if 语句有什么问题?你需要以某种方式做出决定。
  • 开关可以工作,但您需要将其打开以进行扩展。这意味着您应该能够覆盖它,因此该方法不应该是静态的。另一种解决方案是反射,它更灵活。我想看看其他人对此有什么看法,我也遇到过这个问题。
  • @Filkolev 考虑到他正在努力遵守良好的标准和模式,在这里使用反射就像是在打自己的脸,因为你想粉刷你的墙。
  • @Kayaman 我不能再反对了 :)
  • 你们能否支持您的说法,即在这种特殊情况下反射是一种糟糕的编码实践?

标签: java solid-principles open-closed-principle


【解决方案1】:

开闭原则说:

软件实体(类、模块、函数等)应该是开放的 用于扩展,但关闭以供修改。

因此,无论何时引入新的 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 的,但原理是一样的。

【讨论】:

  • 地图看起来很有趣,尤其是在添加新面包店时地图内部不需要更改。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    相关资源
    最近更新 更多