继续讲解第二个重要的设计模式原则——开闭原则~
一.定义
开闭原则,在面向对象编程领域中,规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。
归纳总结如下:
- 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则。
- 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
- 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
- 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
- 所谓对扩展开放:指的是我们系统中的模块、类、方法对它们的提供者(开发者)应该是开放的,提供者可以对系统进行扩展(新增)新的功能。
- 所谓对修改关闭:指的是系统中的模块、类、方法对它们的使用者(调用者)应该是关闭的,使用者使用这些功能时,不会因为提供方新增了功能而导致使用者也进行相应修改。
二.描述
开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性~
- 对软件测试的影响
- 可以提高代码的可复用性
- 可以提高软件的可维护性
三.案例
举个简单的例子,假设你的女票(使用方)有一天收到了你送给她的礼物——这礼物有可能是情书,也有可能是手工书~则实现的代码如下:
//礼物类基类
class gift{
String type;
}
class Letter extends gift{
Letter(){
super.type="Letter";
}
}
class Handwork extends gift{
Handwork(){
super.type="Handwork";
}
}
//使用方类,也就是接收方类
class girlfriend{
public void drawShape(gift g) {
if (g.type == "Letter")
getLetter(g);
else if (g.type == "Handwork")
getHandwork(g);
}
public void getLetter(gift r) {
System.out.println("收到的礼物是情书!");
}
public void getHandwork(gift r) {
System.out.println("收到的礼物是手工书!");
}
}
public class Main {
public static void main(String[] args) {
girlfriend hyh = new girlfriend();
hyh.drawShape(new Letter());
hyh.drawShape(new Handwork());
}
}
这时加入礼物种类添加了一种类型——奢侈品,则对代码的修改如下:
//礼物类基类
class gift{
String type;
}
class Letter extends gift{
Letter(){
super.type="Letter";
}
}
class Handwork extends gift{
Handwork(){
super.type="Handwork";
}
}
class luxury extends gift{
luxury(){
super.type="luxury";
}
}
//使用方类,也就是接收方类
class girlfriend{
public void getgift(gift g) {
if (g.type == "Letter")
getLetter(g);
else if (g.type == "Handwork")
getHandwork(g);
else if (g.type == "Luxury")
getLuxury(g);
}
public void getLetter(gift r) {
System.out.println("收到的礼物是情书!");
}
public void getHandwork(gift r) {
System.out.println("收到的礼物是手工书!");
}
public void getLuxury(gift r) {
System.out.println("收到的礼物是奢侈品!");
}
}
public class Main {
public static void main(String[] args) {
girlfriend hyh = new girlfriend();
hyh.getgift(new Letter());
hyh.getgift(new Handwork());
hyh.getgift(new luxury());
}
}
此时不难发现,不仅修改了提供方(gift类)的代码,也修改了使用方(girlfriend类)的代码,即违反了所谓的开闭原则~(对修改关闭)
也就是说,当发生变更时,提供方是允许修改的,而使用方则不允许,这就是所谓的【对扩展开放,对修改关闭】。
做出如下修改,即可避免:
/**
*
*/
//gift类,基类
abstract class gift {
//声明为一个抽象类~
String type;
public abstract void get();//抽象方法
}
class Letter extends gift {
Letter() {
super.type ="Letter";
}
//重点在于不同的类内部具体实现所谓的方法——即重写
@Override
public void get() {
System.out.println("收到的礼物是情书~");
}
}
class Handwork extends gift {
Handwork() {
super.type =" Handwork";
}
//重点在于不同的类内部具体实现所谓的方法——即重写
@Override
public void get() {
System.out.println("收到的礼物是手工书~");
}
}
class girlfriend {
public void getgift(gift g) {
g.get();
}
}
public class Main {
public static void main(String[] args) {
girlfriend hyh = new girlfriend();
hyh.getgift(new Letter());
hyh.getgift(new Handwork());
}
}
此时我们想要再添加奢侈品Luxury类,只需要修改提供方即可,不需要修改使用方的代码:
/**
*
*/
//gift类,基类
abstract class gift {
//声明为一个抽象类~
String type;
public abstract void get();//抽象方法
}
class Letter extends gift {
Letter() {
super.type ="Letter";
}
//重点在于不同的类内部具体实现所谓的方法——即重写
@Override
public void get() {
System.out.println("收到的礼物是情书~");
}
}
class Handwork extends gift {
Handwork() {
super.type =" Handwork";
}
//重点在于不同的类内部具体实现所谓的方法——即重写
@Override
public void get() {
System.out.println("收到的礼物是手工书~");
}
}
class Luxury extends gift {
Luxury() {
super.type ="Luxury";
}
//重点在于不同的类内部具体实现所谓的方法——即重写
@Override
public void get() {
System.out.println("收到的礼物是奢侈品~");
}
}
class girlfriend {
public void getgift(gift g) {
g.get();
}
}
public class Main {
public static void main(String[] args) {
girlfriend hyh = new girlfriend();
hyh.getgift(new Letter());
hyh.getgift(new Handwork());
hyh.getgift(new Luxury());
}
}
做个总结——牢记对扩展开放,对修改关闭~
(某种意义上,也可以作为【多态】的示例~)
在20世纪90年代,开闭原则被广泛的重新定义由于抽象化接口的使用,在这中间实现可以被改变,多种实现可以被创建,并且多态化的替换不同的实现。
相比梅耶的使用方式,多态开闭原则的定义倡导对抽象基类的继承。接口规约可以通过继承来重用,但是实现不必重用。已存在的接口对于修改是封闭的,并且新的实现必须,至少,实现那个接口。