设计模式-里式替换及开闭原则(OCP)

一:里式替换原则

原则内容:

在子类中尽量不要重写父类的方法(不能改变父类原有的功能)
在软件中,将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常。但是,如果将子类对象换成基类对象,就有可能产生错误和异常。(因为子类对象可能增加了新的属性、方法,甚至重写了父类的方法)

二:开闭原则(OCP)

原则内容:

一个软件实体如类、模块和函数应该扩展开放,对修改关闭用抽象构建框架,用实现扩展细节

扩展开放是对功能提供方而言的,即扩展功能时必定要添加修改代码。
修改关闭时对功能使用方而言的,即功能修改以后,使用方的代码不用修改,仍可使用原先功能。

遵循该原则,可以实现当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改(少修改)已有的代码来实现变化。

下边举一个栗子,再回头理解“功能提供方”、“功能使用方”

实现一个画图的功能

图形有很多种,所以我们要把所有图形,抽象出一个实体,即图形类

//图形类
class Shape{
	//图形的类型
	public int s_type;
	/**
	 * 定义了图形公共的方法属性、方法
	 * 此处为了简便,省略不写
	 */
}

当前的需求是画矩形、圆形,所以让矩形、圆形分别继承图形类,并在构造方法中,初始化图形类型

//矩形
class Rectangle extends Shape{
	public Rectangle() {
		//图形类型设置为1,表示矩形
		super.s_type=1;
	}
}
//圆形
class Circle extends Shape{
	public Circle() {
		//图形类型设置为2,表示圆形
		super.s_type=2;
	}
}

下面,新建一个绘图类(功能使用方),根据传入类型不同,绘制不同的图形,代码如下:

//用户绘图的类(这个类就相当于上边提到的 功能使用方 )
class GraphicEditor{
	public void drawShape(Shape s) {
		//根据类型绘制不同的图形
        if(s.s_type==1) {
            //绘制矩形
			drawRectangle(s);
		}else if(s.s_type==2) {
            //绘制圆形
			drawCircle(s);
		}
	}
	//绘制矩形
	private void drawRectangle(Shape r) {
		System.out.println("绘制矩形");
	}
	//绘制圆形
	private void drawCircle(Shape c) {
		System.out.println("绘制圆形");
	}
}

但是如果需要新增一个功能:绘制三角形,则代码改动较多 修改地方有:

新增Triangle类,继承Shape(功能提供方修改)

//三角形
class Triangle extends Shape{
	public Triangle() {
		//图形类型设置为3,表示三角形
		super.s_type=3;
	}
}

GraphicEditor中新增drawTriangle方法 (功能使用方修改)

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

GraphicEditor中drawShape方法的if else 语句也需要修改(功能使用方修改)

public void drawShape(Shape s) {
	if(s.s_type==1) {
		drawRectangle(s);
	}else if(s.s_type==2) {
		drawCircle(s);
	}else if(s.s_type==3){
		drawTriangle(s);
	}
}

这种修改方法简单,易操作,但是违反了OCP原则:对扩展开放,对修改关闭。即我们在给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码。

但是刚刚的修改中,GraphicEditor新增了drawTriangle方法,且drawShape方法体内做了修改,即:**功能使用方做了大量修改。**违反了开闭原则。

下面介绍一个新的方法:

将画图的方法(GraphicEditor类中的drawRectangle、drawCircle、drawTriangle方法),集成到具体图形类中。
将Shape类变为抽象类,其内有抽象方法draw,具体如何实现交由其子类完成。

代码如下:

//抽象图形类
abstract class Shape{
	//图形的类型
	public int s_type;
	//抽象方法-画图
	abstract public void draw();
}

//矩形
class Rectangle extends Shape{
	public Rectangle() {
		//图形类型设置为1,表示矩形
		super.s_type=1;
	}
	@Override
	public void draw() {
		System.out.println("绘制矩形");
	}
}

//图形
class Circle extends Shape{
	public Circle() {
		//图形类型设置为2,表示图形
		super.s_type=2;
	}
	@Override
	public void draw() {
		System.out.println("绘制圆形");
	}
}

//三角形
class Triangle extends Shape{
	public Triangle() {
		//图形类型设置为3,表示三角形
		super.s_type=3;
	}
	@Override
	public void draw() {
		System.out.println("绘制三角形");
	}
}

GraphicEditor类的代码修改如下:

//用户绘图的类
class GraphicEditor{
	public void drawShape(Shape s) {
		s.draw();
	}
}

这样在添加新的图形时,只需要添加新的图形实体类,并实现draw方法,使用法GraphicEditor不需要做修改

当然,这个栗子也有不恰当的地方,相信很多读者,一开始就能想到把画图的方法draw()写在抽象类Shape中,然后由不同的子类去继承并实现该方法。该栗子的最终目的是为了理解开闭原则OCP:对扩展开放,对修改关闭

初学设计模式,本人学习过程中,所作笔记,希望对你有帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值