介绍

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

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

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

例子引入

我们要实现一个画图的功能,能够画出圆形、矩形、三角形等,最常见的思路就是利用面向对象的思想,抽象出一个所有图形对象的基类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原则。

DesignPattern系列__05开闭原则的更多相关文章

  1. C#设计模式系列:开闭原则(Open Close Principle)

    1.开闭原则简介 开闭原则对扩展开放,对修改关闭,开闭原则是面向对象设计中可复用设计的基石. 2.开闭原则的实现 实现开闭原则的关键就在于抽象,把系统的所有可能的行为抽象成一个抽象底层,这个抽象底层规 ...

  2. 深入理解JavaScript系列(7):S.O.L.I.D五大原则之开闭原则OCP

    前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第2篇,开闭原则OCP(The Open/Closed Principle ). 开闭原则的描述是: Software ...

  3. C#软件设计——小话设计模式原则之:开闭原则OCP

    前言:这篇继续来看看开闭原则.废话少说,直接入正题. 软件设计原则系列文章索引 C#软件设计——小话设计模式原则之:依赖倒置原则DIP C#软件设计——小话设计模式原则之:单一职责原则SRP C#软件 ...

  4. 最简单直接地理解Java软件设计原则之开闭原则

    写在前面 本文属于Java软件设计原则系列文章的其中一篇,后续会继续分享其他的原则.想以最简单的方式,最直观的demo去彻底理解设计原则.文章属于个人整理.也欢迎大家提出不同的想法. 首先是一些理论性 ...

  5. 设计原则:开闭原则(OCP)

    1.什么是开闭原则 开闭原则的英文是Open Closed Principle,缩写就是OCP.其定义如下: 软件实体(模块.类.方法等)应该"对扩展开放.对修改关闭". 从定义上 ...

  6. 设计模式之六大原则——开闭原则(OCP)

    转载于: http://www.cnblogs.com/muzongyan/archive/2010/08/05/1793454.html 开闭原则(Open Closed Principle)是Ja ...

  7. 开放-封闭原则(OCP)开-闭原则 和 依赖倒转原则,单一职责原则

    单一职责原则 1.单一职责原则(SRP),就一个类而言,应该仅有一个引起它变化的原因 2.如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会消弱或抑制这个类完成其他职责的能力. ...

  8. [转]设计模式之六大原则——开闭原则(OCP)

    原文地址:http://www.cnblogs.com/muzongyan/archive/2010/08/05/1793454.html 开闭原则(Open Closed Principle)是Ja ...

  9. Head First 设计模式 --3 装饰者模式 开闭原则

    装饰者模式:动态的将责任附加到对象上,若要扩展功能,装饰者提供了比集成更有弹性的替代方案.设计原则:1:封装变化2:多用组合,少用继承3:针对接口编程,不针对实现编程4:为对象之间的松耦合设计而努力5 ...

随机推荐

  1. Android之控件学习

    文本域,类似于HTML里的textarea <EditText android:id="@+id/edit_text" android:layout_width=" ...

  2. spring boot 2.0 thymeleaf调试时正常,打包后运行报错. 找不到模板文件.

    使用th:fragment  定义模板 使用 th:replace  来添加模板到需要的地方. 使用时发现一个非常奇怪的问题. 本机idea 调试环境一切正常, 但是打成jar包以后报错,提示找不到对 ...

  3. php设计模式-责任链模式

    责任链模式更像是一种简化多种场景下调用处理的一种设计模式,特别适合if-else分支判断很多的场景.比如是根据不同会员等级给予不同的优惠力度. 它的定义:对象的调用是由下家的应用连接起来的处理链.一直 ...

  4. 手把手教你实现"短信轰炸"

    手把手教你实现"短信轰炸" 我这里采用简单易懂的语言--"Python3"来实现   实现前的准备:             1,电脑,谷歌浏览器 2,pyth ...

  5. XAML与C#与WPF三者到底有什么关系?

    XAML是.NET体系开发程序或者网页时前台编程的一种布局方式或者说开发语言,可以比较自由的用标签的方式进行布局,借鉴了HTML和XML等语言的风格,并且加入了一些动画等的实现.C#则是后台逻辑开发用 ...

  6. Java学习笔记之---方法和数组

    Java学习笔记之---方法与数组 (一)方法 (1)什么是方法? 方法是解决一类问题的步骤的有序组合 方法包含于类或对象中 方法在程序中被创建,在其他地方被引用 (2)方法的优点 使程序变得更简短而 ...

  7. git分支创建与切换

    1. 场景描述 新版本迭代上线完成,为了保持当前版本稳定性及可回退等需求,需要切换新的分支用于下一版本的迭代开发. 2. 解决方案 2.1 切换前工作. 因发布上线当天有可能存在临时更改文件而未上传g ...

  8. centos 安装Python3 及对应的pip

    安装Python3安装Python依赖:yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqli ...

  9. 字符串的排列(剑指offer)

    题目描述: 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 思路: 利用 ...

  10. 模拟ssh远程执行命令,粘包问题,基于socketserver实现并发的socket

    06.27自我总结 1.模拟ssh远程执行命令 利用套接字编来进行远程执行命令 服务端 from socket import * import subprocess server = socket(A ...