DesignPattern系列__05开闭原则

介绍

开闭原则是编程设计中最基本、最重要的原则。

定义:一个软件实体如类、方法和模块等,应该对扩展(提供方)开放,对修改(使用方)关闭。用抽象构建框架,用实现扩展细节。

也就是说,在需求发生新的变化时,我们不应该修改原来的代码,而应该通过扩展来满足新的需求。

例子引入

我们要实现一个画图的功能,能够画出圆形、矩形、三角形等,最常见的思路就是利用面向对象的思想,抽象出一个所有图形对象的基类Shape,具体的图形如矩形、圆形灯继承自该类。在Shape中定义一个变量shapeType来保存具体的图形的类型。
定义一个绘图类GraphicEditor,在执行具体的绘图方法(如画一个矩形)时,根据传入的shapeType来执行对应图形的绘制方法。
类图设计如下:

功能初步实现了,但是有什么缺陷吗?让我们来给项目适当的“松松土”:现在我们想要画一个三角形,如何实现呢?
也很简单:再定义一个类Triangle继承自Shape,并且在GraphicEditor修改方法,加入对三角形的类型判断,具体的代码如下:

public class Ocp {
    public static void main(String[] args) {
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());
        graphicEditor.drawShape(new Circle());
        graphicEditor.drawShape(new Triangle());
    }
}

//这是一个用于绘图的类 [使用方]
class GraphicEditor {
    //接收Shape对象,然后根据type,来绘制不同的图形
    public void drawShape(Shape s) {
        if (s.shapeType == 1)
            drawRectangle(s);
        else if (s.shapeType == 2)
            drawCircle(s);
        else if (s.shapeType == 3)
            drawTriangle(s);
    }

    //绘制矩形
    public void drawRectangle(Shape r) {
        System.out.println(" 绘制矩形 ");
    }

    //绘制圆形
    public void drawCircle(Shape r) {
        System.out.println(" 绘制圆形 ");
    }

    //绘制三角形
    public void drawTriangle(Shape r) {
        System.out.println(" 绘制三角形 ");
    }
}

class Shape {
    int shapeType;
}

class Rectangle extends Shape {
    public Rectangle() {
        super.shapeType = 1;
    }
}

class Circle extends Shape {
    public Circle() {
        super.shapeType = 2;
    }
}

//新增画三角形
class Triangle extends Shape {
    Triangle() {
        super.shapeType = 3;
    }
}

OK,新的需求也实现了,现在,发现问题了吗?
我们每次遇见新需求之外,除了定义新的图形类,还要对类GraphicEditor进行修改。
根据前面提到的“开闭原则”中提到的,应该对修改关闭,对扩展开放,我们不应该修改类GraphicEditor,这样会严重影响代码的稳定性和可维护性。
现在,我们尝试按照“开闭原则”来实现这个功能。
根据“开闭原则”,我们应该封装变化,在这里,我们在Shape中定义一个抽象的绘图方法,并在各自实现类内进行具体实现。在类GraphicEditor中,只定义一个接受参数为抽象(Shape)的方法,使得类不再去受到类型影响,满足了“开闭原则”。
具体的代码如下:

public class Ocp {
    public static void main(String[] args) {
        //使用看看存在的问题
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());
        graphicEditor.drawShape(new Circle());
        graphicEditor.drawShape(new Triangle());
    }
}

//这是一个用于绘图的类 [使用方]
class GraphicEditor {
    //接收Shape对象,然后根据type,来绘制不同的图形
    public void drawShape(Shape s) {
        s.draw();
    }

}

abstract class Shape {
    int shapeType;
    //定义一个抽象的画图方法
    public abstract void draw();
}

class Rectangle extends Shape {
    public Rectangle() {
        super.shapeType = 1;
    }

    @Override
    public void draw() {
        System.out.println("绘制矩形");
    }
}

class Circle extends Shape {
    public Circle() {
        super.shapeType = 2;
    }

    @Override
    public void draw() {
        System.out.println("绘制圆形");
    }
}

//新增画三角形
class Triangle extends Shape {
    Triangle() {
        super.shapeType = 3;
    }

    @Override
    public void draw() {
        System.out.println("绘制三角形");
    }
}

在改进的代码中,我们将画图方法进行抽象,定义在基类Shape中,并通过子类各自实现对应的画图方法。并且,对于类GraphicEditor而言,只需定义一个接受基类作为参数的方法即可,代码变得整洁、易于维护。

使用注意事项

在实际使用中,需要注意以下几个方面:

1.抽象约束

这点的含义包含三个意思:
1.通过接口或者抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或者抽象类中没有定义的public方法;
2.参数类型,要尽量使用接口或者抽象类,不应该使用实现类。
3.抽象层作为约束,应该尽量保持稳定,一旦确定不容修改。

2.元数据控制模块行为

在实际开发中,要尽量使用注解或者配置文件来控制程序的行为,减少重复开发。比如搭建ssm框架中,使用注解或者配置文件来注入bean。

3.约定优于配置

对于大家普遍遵循的章程或者约定,我们要严格遵守,这样能减少配置文件的编写。比如MyBatis框架对xml文件的扫描,默认会去和接口同名的包下去查找,只要我们遵循这一约定, 就无需格外配置。

4.封装变化

对变化的封装包括两点:
1.相同的变化,应该封装到一个接口或者抽象类中;
2.不同的变化,应该封装到不同的接口或者抽象类中,不应该有两个不同的变化封装在一个接口或者抽象类中。

一句话总结

开闭原则,是一切设计模式的基础,可以说其他原则和设计模式都是为了实现开闭i原则。

(0)

相关推荐

  • 图解Java设计模式之设计模式七大原则

    图解Java设计模式之设计模式七大原则 2.1 设计模式的目的 2.2 设计模式七大原则 2.3 单一职责原则 2.3.1 基本介绍 2.3.2 应用实例 2.4 接口隔离原则(Interface S ...

  • 设计模式的七大原则(5) --开闭原则

    前言 我们已经学习了单一职责原则,依赖倒置原则,接口隔离原则,李氏替换原则.可以说前面几个原则都是为了开闭原则奠定基础. 我们写的程序由于实际的情况可以一定程度上违背各种设计原则.但是,开闭原则我认为 ...

  • 【C++设计模式二】C++工厂模式

    (1)定义 简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑.为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂, ...

  • 设计模式——六大设计原则

    文章目录 一.单一职责原则 二.里式替换原则 三.依赖倒置原则 四.接口隔离原则 五.迪米特法则 六.开闭原则 一.单一职责原则 单一职责原则简称 SRP,他想表达的就是字面意思,一个类只承担一个职责 ...

  • 设计模式六大原则:开闭原则

    开闭原则(Open Close Principle): Software entities (classes, modules, functions, etc.) should be open for ...

  • 阴阳六经及阖枢开闭解释

    足太阳膀胱经解析 足太阳膀胱经,就是足三阳经的"开".<素问·灵兰秘典论>曰:"膀胱者,州都之官,津液藏焉,气化则能出矣."什么意思呢? 州都:州, ...

  • 登陆香港,mastermind JAPAN x F.C.R.B. 联名系列即将开售

    经历了歇业后不久,重振旗鼓的mastermind JAPAN继续开展着自己的骷髅创意,尤其是早先曝光的F.C.R.B. 联名也是重点关注对象之一.近日相关单品将再次登陆香港.一方面是大打暗黑及&quo ...

  • 地产成本管控的路上,离不开的原则!

    -  01  - 楔 子 房住不炒.地产五条红线的压迫下,房地产企业的焦虑程度越来越强烈,压力传导下的地产人,更是要面临地产改革.扁平化以及行业千变万化的趋势.在这种大趋势下,个人专业及能力越来越受到 ...

  • 自动开闭器接点组使用注意事项

    自动开闭器接点组使用注意事项

  • ZDJ9转辙机自动开闭器注油重点位置

    近期,管内ZDJ9型转辙机发生自动开闭器接点''蔫打''问题.经过试验.分解.分析,确认有以下几个主要原因: 1.动.静接点脏: 2.与动接点轴相连的两个短垫套表面.调整板表面缺油. 下面对第2条进行 ...

  • Keeppley 国玩系列 K18001 开运火锅店 新中式建筑 测评!

    咱们在2月份测评过Keeppley的一款编号为K18002的栖云小筑: Keeppley 国玩系列 K18002 栖云小筑 新中式建筑 测评! 而今天带来的K18001开运火锅店是这个"新中 ...

  • OpenCV探索之路(四):膨胀、腐蚀、开闭运算

    腐蚀和膨胀是最基本的形态学运算. 腐蚀和膨胀是针对白色部分(高亮部分)而言的. 膨胀就是对图像高亮部分进行"领域扩张",效果图拥有比原图更大的高亮区域:腐蚀是原图中的高亮区域被蚕食 ...