https://blog.csdn.net/weixin_44036154/article/details/109026656
目录:
在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据 7 条原则来开发程序,从而提高软件开发效率、节约软件开发成本和维护成本。
这 7 种设计原则是软件设计模式必须尽量遵循的原则,各种原则要求的侧重点不同。其中,开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。
1、开闭原则
(1)原则定义:
软件实体应当对扩展开放,对修改关闭,这就是开闭原则的经典定义。
这里的软件实体包括以下几个部分:
- 项目中划分出的模块
- 类与接口
- 方法
(2)实现原理:
(3)实例展示:
/** * 定义课程接口 */ public interface ICourse { String getName(); // 获取课程名称 Double getPrice(); // 获取课程价格 Integer getType(); // 获取课程类型 } /** * 英语课程接口实现 */ public class EnglishCourse implements ICourse { private String name; private Double price; private Integer type; //省略get,set,空参,满参 } // 测试 public class Main { public static void main(String[] args) { ICourse course = new EnglishCourse("小学英语", 199D, "Mr.Zhang"); System.out.println( "课程名字:" + course.getName() + " " + "课程价格:" + course.getPrice() + " " + "课程作者:" + course.getAuthor() ); } }
项目上线,但是出现了节假日打折的情况出现,现在有以下这几种方法去修改:
1:修改接口(不可取,修改接口时其他的代码也得改!)
2:修改实现类(不可取,这样会有两个获取价格的方法!)
3:扩展实现方法(可取,不改变原有代码,功能可实现!)
直接添加一个子类 SaleEnglishCourse ,重写 getPrice()方法,这个方案对源代码没有影响,符合开闭原则,所以是可执行的方案
public class SaleEnglishCourse extends EnglishCourse { public SaleEnglishCourse(String name, Double price, String author) { super(name, price, author); } @Override public Double getPrice() { return super.getPrice() * 0.85; } }
(4)开闭原则的作用
开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性。具体来说,其作用如下。
1. 对软件测试的影响
软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行。
2. 可以提高代码的可复用性
粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性。
3. 可以提高软件的可维护性
遵守开闭原则的软件,其稳定性高和延续性强,从而易于扩展和维护。
2、里氏替换原则
(1)原则定义:
继承必须确保超类(被继承的类称为超类,继承的类称为子类)所拥有的性质在子类中仍然成立。
(2)实现原理:
1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
4、覆写或实现父类的方法时输出结果可以被缩小
(3)实例展示:
1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
2、子类可以有自己的个性
在继承父类属性和方法的同时,每个子类也都可以有自己的个性,在父类的基础上扩展自己的功能。前面其实已经提到,当功能扩展时,子类尽量不要重写父类的方法,而是另写一个方法,所以对上面的代码加以更改,使其符合里氏替换原则。
(略)
3、覆盖或实现父类的方法时输入参数可以被放大
当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
public class ParentClazz { public void say(String str) { System.out.println("parent execute say " + str); } } public class ChildClazz extends ParentClazz { public void say(CharSequence str) { System.out.println("child execute say " + str); } } // 执行结果: // parent execute say hello // parent execute say hello // 参数大小不一样,一直用的都是string,父类的
4、覆写或实现父类的方法时输出结果可以被缩小
当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
public abstract class Father { public abstract Map hello(); } public class Son extends Father { @Override public Map hello() { HashMap map = new HashMap(); System.out.println("son execute"); return map; } }
(4)里氏替换的作用:
里氏替换原则是实现开闭原则的重要方式之一。
3、依赖倒置原则
(1)原则定义:
依赖倒置原则的原始定义为:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。
(2)实现原理:
依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下4点,就能在项目中满足这个规则。
-
变量的声明类型尽量是接口或者是抽象类。
-
任何类都不应该从具体类派生。
-
使用继承时尽量遵循里氏替换原则。
(3)实例展示
public class T2 { public static void main(String[] args) { IDriver zhangsan = new Driver(); Icar benz = new Benz(); zhangsan.drive(benz); Icar bmw = new BMW(); zhangsan.drive(bmw); } } interface IDriver { // 司机职责就是驾驶汽车 public void drive(Icar car); } class Driver implements IDriver { // 司机职责就是驾驶汽车 @Override public void drive(Icar car) { car.run(); } } interface Icar { // 车的作用就是跑 public void run(); } class Benz implements Icar { // 车的作用就是跑 @Override public void run() { System.out.println("奔驰车跑起来了"); } } class BMW implements Icar { // 车的作用就是跑 @Override public void run() { System.out.println("宝马车跑起来了"); } }
依赖倒置原则的主要作用如下。
-
依赖倒置原则可以提高系统的稳定性。
-
依赖倒置原则可以减少并行开发引起的风险。
-
依赖倒置原则可以提高代码的可读性和可维护性。