开放/封闭原则是不是说我们不能更改类的接口?

Posted

技术标签:

【中文标题】开放/封闭原则是不是说我们不能更改类的接口?【英文标题】:Does Open/Closed Principle say that we can't changed interfaces of our classes?开放/封闭原则是否说我们不能更改类的接口? 【发布时间】:2016-04-03 06:49:16 【问题描述】:

请看这堂课:

public class SomeClass 

public void method1()
    // do something


public void method2()
    // do something



接下来,假设有 10 个类继承了这个类。因此,如果我们将参数添加到 method1(),例如,我们必须更改 10 个类。这与 Open/Closed 原则背道而驰。那么,开闭原则是不是说我们不能改变类的公共接口呢?

【问题讨论】:

您必须更改超过 10 个类。您必须更改将 调用 method1() 的每个类,因为这些 0 参数调用不再有效。我不会像简单的向后兼容性那样担心 OCP。当然,如果你控制了所有的调用代码,那就没问题了。这真的取决于上下文。 programmers.stackexchange.com/questions/310603/… @JonSkeet,所以如果我控制所有调用代码,我可以更改公共接口吗?如果我不控制我必须保存旧版本的方法并添加新版本?之后我可以宣布旧版本已弃用? 【参考方案1】:

是的 - 有点... #8>P

“Closed to changes” 位表示您不应删除 public void method1() 签名,也不应更改其语义(由所有正确实现的具体类提供)。

“对扩展开放” 位允许您(小心地)修改界面,只要之前的界面元素保持原样(结构和语义上)。你可以试试这样的:

public class SomeClass 

    @Deprecated
    default public void method1()
        method1(#SENTINAL#);
    

    public void method1(#TYPE# arg)
        if (arg == #SENTINAL#) 
            // do something old
         else 
            // do something new
        
    

    public void method2()
        // do something
    


注意:如果参数没有有用的 #SENTINAL# 值,则此方法可能不起作用,例如这是一个int,所有值都有效。但是,通常会有一些东西,比如任何负数、MIN 或 MAX 值、空或 null 对象等。当没有这样的哨兵可用时,您可以创建一个私有的公共方法,例如:

public class SomeClass 

    @Deprecated
    default public void method1()
        method1(true);
    

    public void method1(#TYPE# arg)
        method1(false, arg)
    

    private void method1(boolean isOldWay, #TYPE# arg) 
        if(isOldWay) 
            // snore - still old clients
         else 
            // yea! new clients are much greener!
        
    

PS - 我说的是“接口”,即使你正在使用一个类。只需将接口视为类的公共元素,在实现类的同时声明。我通常更喜欢代码到接口,但这不是 OP 的问题,也不会改变我的观点(只是 where 进行了修改 - 特别是如果使用 Java 8 接口默认实现)。

【讨论】:

我不同意“对扩展开放”允许您修改界面 - 您有时可能需要这样做,但这违反了 OCP,而不是它的一部分。 OCP 表示,如果您确实需要重构和修改,那么您以一种对未来扩展开放的方式进行。例如通过访问者/策略模式之类的东西。另见this article by Uncle Bob 嗯,这有点让人毛骨悚然,但我认为只要不需要更改客户端代码就可以了(最多重新编译,但甚至没有一个大括号平滑成正义括号 ::smile::)。诚然,这违反了“纯”OCP,但我很务实地认为,这种精神是通过对界面的完全兼容更改来维持的——不是这就是为什么默认方法实际上已经成为语言的原因? (可惜我们做不到default final... ::haha:: 当然,实用主义始终是关键(这也是为什么它是“原则”而​​不是“规则”的原因——违反它是一种代码味道,但这并不意味着它不应该完成)。【参考方案2】:

这是违反 OCP 的。 接近修改意味着一旦你实现了这个类并对其进行了测试,你就不应该再修改它了。 有一些不可预知的情况,业务需求突然改变,无论你设计得多么好,你都必须修改你的类。 在您的情况下,最简单的方法是通过将这个新参数注入到实现类的构造函数中来添加这个新参数,或者更好的是,注入这个参数的提供者

public class SomeClass       
    IProvider _provider;

    public SomeClass(IProvider provider)
        _provider = provider
    

    public void method1()
        var someInput = _provider.Get();
        // do something
    

    public void method2()
        var someInput = _provider.Get();
        // do something
    

【讨论】:

以上是关于开放/封闭原则是不是说我们不能更改类的接口?的主要内容,如果未能解决你的问题,请参考以下文章

面向对象的五大基本原则

day21接口类和抽象类,隔离原则,开放封闭原则,多态

面向对象原则之一 接口隔离原则

设计模式原则

Charpter04 开放-封闭原则

面向对象原则之一 开放封闭原则(开闭原则)