`

开闭原则(Open Close Principle)

 
阅读更多

定义:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

问题由来:在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试。

解决方案:当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。

         开闭原则是面向对象设计中最基础的设计原则,它指导我们如何建立稳定灵活的系统。开闭原则可能是设计模式六项原则中定义最模糊的一个了,它只告诉我们对扩展开放,对修改关闭,可是到底如何才能做到对扩展开放,对修改关闭,并没有明确的告诉我们。以前,如果有人告诉我“你进行设计的时候一定要遵守开闭原则”,我会觉的他什么都没说,但貌似又什么都说了。因为开闭原则真的太虚了。

         在仔细思考以及仔细阅读很多设计模式的文章后,终于对开闭原则有了一点认识。其实,我们遵循设计模式前面5大原则,以及使用23种设计模式的目的就是遵循开闭原则。也就是说,只要我们对前面5项原则遵守的好了,设计出的软件自然是符合开闭原则的,这个开闭原则更像是前面五项原则遵守程度的“平均得分”,前面5项原则遵守的好,平均分自然就高,说明软件设计开闭原则遵守的好;如果前面5项原则遵守的不好,则说明开闭原则遵守的不好。

         其实笔者认为,开闭原则无非就是想表达这样一层意思:用抽象构建框架,用实现扩展细节因为抽象灵活性好,适应性广,只要抽象的合理,可以基本保持软件架构的稳定。而软件中易变的细节,我们用从抽象派生的实现类来进行扩展,当软件需要发生变化时,我们只需要根据需求重新派生一个实现类来扩展就可以了。当然前提是我们的抽象要合理,要对需求的变更有前瞻性和预见性才行。

         说到这里,再回想一下前面说的5项原则,恰恰是告诉我们用抽象构建框架,用实现扩展细节的注意事项而已:单一职责原则告诉我们实现类要职责单一;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合。而开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭。

         最后说明一下如何去遵守这六个原则。对这六个原则的遵守并不是是和否的问题,而是多和少的问题,也就是说,我们一般不会说有没有遵守,而是说遵守程度的多少。任何事都是过犹不及,设计模式的六个设计原则也是一样,制定这六个原则的目的并不是要我们刻板的遵守他们,而需要根据实际情况灵活运用。对他们的遵守程度只要在一个合理的范围内,就算是良好的设计。我们用一幅图来说明一下。

        图中的每一条维度各代表一项原则,我们依据对这项原则的遵守程度在维度上画一个点,则如果对这项原则遵守的合理的话,这个点应该落在红色的同心圆内部;如果遵守的差,点将会在小圆内部;如果过度遵守,点将会落在大圆外部。一个良好的设计体现在图中,应该是六个顶点都在同心圆中的六边形。

        在上图中,设计1、设计2属于良好的设计,他们对六项原则的遵守程度都在合理的范围内;设计3、设计4设计虽然有些不足,但也基本可以接受;设计5则严重不足,对各项原则都没有很好的遵守;而设计6则遵守过渡了,设计5和设计6都是迫切需要重构的设计。

 

下面是使用开闭原则的一个简单示例,虽有些不准确,但是是这个意思(领会精神)

定义一个接口,寻找美女

package com.loulijun.chapter6;
 
public interface IFindGirl {
    //年龄
    public int getAge();
    //姓名
    public String getName();
    //长相
    public String getFace();
    //身材
    public String getFigure();
}

实现这个接口

package com.loulijun.chapter6;
 
public class FindGirl implements IFindGirl {
    private String name;
    private int age;
    private String face;
    private String figure;
     
    public FindGirl(String name, int age, String face, String figure)
    {
        this.name = name;
        this.age = age;
        this.face = face;
        this.figure = figure;
    }
 
    @Override
    public int getAge() {
        return age;
    }
 
    @Override
    public String getFace() {
        return face;
    }
 
    @Override
    public String getFigure() {
        return figure;
    }
 
    @Override
    public String getName() {
        return name;
    }
     
 
}

场景:大街上

package com.loulijun.chapter6;
 
import java.text.NumberFormat;
import java.util.ArrayList;
 
public class Street {
    private final static ArrayList<IFindGirl> girls = new ArrayList<IFindGirl>();
    //静态初始化块
    static
    {
        girls.add(new FindGirl("张含韵",23,"可爱型","165cm/47kg"));
        girls.add(new FindGirl("高圆圆",33,"时尚型","165cm/48kg"));
        girls.add(new FindGirl("章泽天",19,"清纯型","168cm/47kg"));
    }
    public static void main(String args[])
    {
        System.out.println("----------美女在这里----------");
        for(IFindGirl girl:girls)
        {
            System.out.println("姓名:"+girl.getName()+" 年龄:"+girl.getAge()+
                    "  长相:"+girl.getFace()+"  身材:"+girl.getFigure());
        }
    }
}

运行结果:

----------美女在这里----------
姓名:张含韵 年龄:23 长相:可爱型 身材:165cm/47kg
姓名:高圆圆 年龄:33 长相:时尚型 身材:165cm/48kg
姓名:章泽天 年龄:19 长相:清纯型 身材:168cm/47kg

但是如果想独立分出一个外国美女的类别的话(比如增加一个国籍),可以通过修改接口、修改实现类、通过扩展来实现。

如果修改接口,也就意味着修改实现类,这样对项目的变动太大了,所以不推荐

如果修改实现类,这样虽能解决问题,但是明显有些牵强,如果需要其他变动的时候会显得逻辑混乱

所以,通过扩展来实现是最简单的方式

如何扩展:

可以定义一个IForeigner接口继承自IFindGirl,在IForeigner接口中添加国籍属性getCountry(),然后实现这个接口即可,然后就只需要在场景类中做稍微修改就可以了

package com.loulijun.chapter6;
 
public interface IForeigner extends IFindGirl {
    //国籍
    public String getCountry();
}

实现接口

package com.loulijun.chapter6;
 
public class ForeignerGirl implements IForeigner {
    private String name;
    private int age;
    private String country;
    private String face;
    private String figure;
     
    public ForeignerGirl(String name, int age, String country, String face, String figure)
    {
        this.name = name;
        this.age = age;
        this.country = country;
        this.face =face;
        this.figure = figure;
    }
    @Override
    public String getCountry() {
        // TODO Auto-generated method stub
        return country;
    }
 
    @Override
    public int getAge() {
        // TODO Auto-generated method stub
        return age;
    }
 
    @Override
    public String getFace() {
        // TODO Auto-generated method stub
        return face;
    }
 
    @Override
    public String getFigure() {
        // TODO Auto-generated method stub
        return figure;
    }
 
    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return name;
    }
 
}

然后在场景类中只需要修改如下代码即可,其他不变

girls.add(new ForeignerGirl("Avirl",28,"美国","性感型","160cm/45kg"));

不过这些设计原则到不是绝对的,而是根据项目需求,实际需求来定夺使用

分享到:
评论

相关推荐

    【原创】Open close principle sample, state pattern, template method pattern

    本篇将深入探讨“开闭原则”(Open Close Principle,OCP)、“状态模式”以及“模板方法模式”,并提供一个结合这三种模式的实际代码示例。 首先,我们来理解“开闭原则”(OCP)。这是面向对象设计的一个基本原则...

    设计模式uml.vsdx

    2.设计模式的六大原则 1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要... 3.Java的23中设计模式 从这一块开始,我们详细介绍Java中23种设计模式的概念,应用...

    24种设计模式介绍与6大设计原则

    1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和...

    Java23种基本的设计模式整料整理学习源码示例zip

    开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。...

    Java 23种设计模式详解

    1、开闭原则(Open Close Principle) 2、里氏代换原则(Liskov Substitution Principle) 3、依赖倒转原则(Dependence Inversion Principle) 4、接口隔离原则(Interface Segregation Principle) 5、迪米特法则...

    Java 设计模式

    1、开闭原则(Open Close Principle)  对扩展开放,对修改关闭。 2、里氏代换原则(Liskov Substitution Principle)  只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生...

    设计模式Demo

    1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和...

    Java面向对象设计原则.docx

    原则3: 开闭原则 Open-Close Principle(OCP) 即对扩展开放,对修改关闭。这是另一种非常棒的设计原则,可以防止其他人更改已经测试好的代码。理论上,可以在不修改原有的模块的基础上,扩展功能。这也是开闭原则的...

    软件设计原则.pptx

    1. **开闭原则 (Open Close Principle, OCP)**:这一原则要求软件实体(如类、模块、函数等)应对于扩展开放,而对于修改封闭。这意味着在面对新的需求时,我们应该尽可能地通过添加新代码而不是修改已有代码来实现...

    软件设计的七大原则(OOD)

    二、OCP(Open-Close Principle):开闭原则 OCP是软件设计的七大原则之一,它的定义是:软件实体(类、模块、函数/方法等等)对于扩展应该是开放的,对于修改应该是封闭的。OCP可以提高软件模块的可重用性和可维护...

    design_pattern:关于设计模式的理解

    设计模式的六大原则1、开闭原则(Open Close Principle)开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,...

    java23种设计模式详细讲解

    - 开闭原则(Open Close Principle):软件实体应当对扩展开放,对修改关闭。 通过以上知识点的讲解,我们可以看到,设计模式不仅可以帮助我们解决实际编程中的具体问题,还可以提升代码的可读性、可维护性,以及...

    design-pattern-in-[removed]JavaScript中的设计模式(JavaScript的设计模式)

    开闭原则(Open Close Principle) 里氏代换原则(Liskov Substitution Principle) 依赖倒转原则(Dependency Inversion Principle) 接口隔离原则(接口隔离原则) 迪米特法则,又称最少知道原则(Demeter ...

    Java的常用设计模式

    开闭原则(Open Close Principle)  开闭原则是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括是:为了使程序的扩展性好,易于维护和升级。想...

    Open-close-principle

    #OCP 如果我们希望添加一个新的三角形形状,那么我们所做的就是添加 另一个实现形状接口的子类。 无需更改 GraphicalEditor。 好处:- • 无需单元测试。 • 无需了解GraphicEditor 的源代码。...

    酒店客房管理系统源码java-design_model:23种设计模式学习记录

    1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级...

    JAVA设计模式的六大原则

    #### 一、开闭原则(Open-Close Principle) **定义:** 开闭原则强调的是软件实体(类、模块、函数等)应该是可扩展的但不可修改的,即软件实体应该对扩展开放,对修改关闭。 **实践方法:** - **接口或抽象类...

    wxpdesignpattern:wxpdesignpattern

    一、开闭原则(Open Close Principle)### 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。 所以一句话概括就是:为了使程序的扩展性好,易于维护...

    酒店客房管理系统源码java-DesignPattern:我总结的一些设计模式学习

    开闭原则(Open Close Principle):对扩展开放,对修改关闭。 在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是: 为了使程序的扩展性好,易于维护和升级。想要达到这样的...

    DisignPatterns:设计模式学习

    #设计模式的六大原则##1、开闭原则(Open Close Principle)开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展...

Global site tag (gtag.js) - Google Analytics