Java真的不难(三十七)设计模式的六大原则(1)

设计模式的六大原则(1)

在之前的设计模式文章中,多多少少遇到过好多原则,比如最常见的开闭原则、里氏代换原则等等,但是并没有具体说这些原则到底是什么内容,因此这篇文章就大概的说一下设计模式的六大原则。这样也方便在之后学习中遇到这些原则名词后可以更好的理解为什么这个模式不符合这个原则或者符合这个原则。这些内容很多也是整理自互联网和其他技术博客。


1、开闭原则(Open Close Principle)

开闭原则的含义是:
当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求

开闭原则的作用:

  1. 对软件测试的影响: 软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行
  2. 可以提高代码的可复用性: 粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性
  3. 可以提高软件的可维护性: 遵守开闭原则的软件,其稳定性高和延续性强,从而易于扩展和维护。

简单的说开闭原则的意思是:

对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类

比如这个计算面积的案例:

接口:

public interface ICalculationArea {

    //计算长方形的面积
    double rectangle(double x,double y);

    //计算三角形面积
    double triangle(double x,double y,double z);

    //计算圆形面积
    double circular(double r);
}

实现类:

public class CalculationArea implements ICalculationArea{

    //我们默认π基本上都是以3.14来计算
    private final static double π = 3.14;

    //长方形面积
    @Override
    public double rectangle(double x, double y) {
        return x*y;
    }

    //三角形面积
    @Override
    public double triangle(double x, double y, double z) {
        double p = (x+y+z)/2;
        return Math.sqrt(p*(p-x)*(p-y)*(p-z));
    }

    //圆形面积
    @Override
    public double circular(double r) {
        return π*r*r;
    }
}

OK,这都是没问题的,但是如果万一有些人在使用圆形的计算面积时候,对π的精度要求比较高,需要修改成3.1415926,该怎么办?

为了符合开闭原则:扩展开放,修改关闭,我们决不允许直接在类里面去修改π值,二=而是再去扩展一个高精度的圆形面积计算类:

//实现自己的需求,符合开闭原则,没有修改原来的参数
public class CalculationAreaExt extends CalculationArea {

    private final static double π = 3.1415926;

    @Override
    public double circular(double r){
        return π*r*r;
    }
}

测试类:


public class Test {
    public static void main(String[] args) {

        CalculationAreaExt c = new CalculationAreaExt();
        System.out.println(c.circular(5));

    }
}

输出:

78.539815

2、里氏代换原则(Liskov Substitution Principle)

里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

里氏替换原则的作用:

  1. 里氏替换原则是实现开闭原则的重要方式之一
  2. 它克服了继承中重写父类造成的可复用性变差的缺点
  3. 它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性
  4. 加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性、可扩展性,降低需求变更时引入的风险

里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

里氏替换原则在“鱼和气球鱼(玩具)”实例中的应用:

在这里插入图片描述

鱼类:

/**
 * 鱼类
 */
public class Fish {

    double SwimmingSpeed;  //游泳速度


    public void setSpeed(double swimmingSpeed) {
        SwimmingSpeed = swimmingSpeed;
    }

    public double getSwimmingTime(double distance){
        return (distance/SwimmingSpeed);
    }
}

鲨鱼类:

/**
 * 鲨鱼类
 */

public class Shark extends Fish{
    //继承父类方法
}

气球鱼类(是玩具,不会游泳):

/**
 * 因为是气球鱼,属于玩具,不会游泳
 */
public class BalloonFish extends Fish{

    public void setSpeed(double speed){
        SwimmingSpeed = 0;
    }

}

测试类:


public class Test {
    public static void main(String[] args) {

        Fish fish1 = new Shark();
        Fish fish2 = new BalloonFish();

        fish1.setSpeed(50);
        fish2.setSpeed(50);

        System.out.println("如果两条鱼需要游100公里");

        try{
            System.out.println("鲨鱼将游"+fish1.getSwimmingTime(100)+"小时");
            System.out.println("气球鱼将游"+fish2.getSwimmingTime(100)+"小时");
        } catch (Exception e) {
            System.out.println("程序运行有误!");
        }

    }
}

输出结果:
在这里插入图片描述
程序运行错误的原因是:
气球鱼类重写了鱼类的 setSpeed(double speed) 方法,这违背了里氏替换原则。

正确的做法是: 取消气球鱼原来的继承关系,定义鱼和气球鱼的更一般的父类,如动物类,它们都有奔跑的能力。气球鱼的游泳速度虽然为 0,但在空中并不是静止的,速度不为 0(有风就会飘动),也可以计算出其移动奔跑 100千米所要花费的时间


在这里插入图片描述

  • 28
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 40
    评论
评论 40
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

热爱飞行的小应学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值