可维护性有关的构造原理

SOLID 原则提供了五条指导思想,如果我们遵从它们的话, 将可以显著的提升我们软件可维护性。

SRP 单一责任原则(The Single Responsibility Principle)

  1. 单一职责原则(SRP)声明:“引起类变化的因素永远不要多余一个”。这意味着你需要设计你的类,使得每个类都只有一个目的。这并不意味着每个类应该只有一个方法,而是说类中所有的方法都要与该类的主要功能相关。那些有多个职责的类,应该被分成新的类。

    ---- One class, one responsibility

  2. SRP是最简单的原则,却是最难做好的原则。

来个反例:图1 SRP反例

OCP 开放封闭原则(The Open Closed Principle)

  1. 软件实体应该是:

    对扩展开放
    对修改封闭

  2. 这个原则是诸多面向对象编程原则中最抽象、最难理解的一个。

  3. 关键解决方案:抽象技术。 使用继承和组合来改变类的行为。

第一个栗子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TtKvzJZh-1596860568311)(https://i.loli.net/2020/05/19/HMlbcEqzZvURIoa.png)]

第二个例子:以书店销售书籍为例

书籍接口

public interface IBook{
  public String getName();
  public String getPrice();
  public String getAuthor();
}

小说类

public class NovelBook implements IBook{
   private String name;
   private int price;
   private String author;

   public NovelBook(String name,int price,String author){
     this.name = name;
     this.price = price;
     this.author = author;
   }

   public String getAutor(){
     return this.author;
   }

   public String getName(){
     return this.name;
   }  

   public int getPrice(){
     return this.price;
   } 
}

客户端

public class Client{
   public static void main(Strings[] args){
     IBook novel = new NovelBook("深入理解计算机系统",100,"CMU");
     System.out.println("书籍名字:"+novel.getName()+"书籍作者:"+novel.getAuthor()+"书籍价格:"+novel.getPrice());
   }

}

接下来,到了世界读书日,书店打折,需要做出改变。有一下几种修改方法:

  • 修改接口

    IBook里添加方法getOffPrice() (接口应该是稳定且可靠,不应该经常发生改变)

  • 修改实现类

    NovelBook里将getPrice()方法修改为打折价格 (我们如果getPrice()方法中只需要读取书籍的打折前的价格呢?)
    NovelBook里再增加getOffPrice()方法 (DIP原则(后文会讲到)要求尽量用接口定义变量,只在具体实现类里新增方法,用接口定义的变量无法使用这个方法)

  • 实现拓展类

    增加一个OffNovelBook类继承NovelBook,重写getPrice()方法,修改为打折价格

public class OffNovelBook extends NovelBook{

   public OffNovelBook(String name,int price,String author){
      super(name,price,author);
   }

   //覆写价格方法
   public int getPrice(){
        return this.price * 0.9;
     }     
   } 
}

LSP 里氏替换原则(The Liskov Substitution Principle)

  1. 两种定义:

    • 如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换为o2,程序P的行为没有发生变化,那么类型S是类型T的子类型。
    • 所有引用基类的地方必须透明的使用其子类的对象。(只要父类能出现的地方子类也可以出现,而且替换为子类不会产生任何错误或异常,但是反过来就不行,有子类出现的地方,父类未必就能适应。)
  2. 里氏替换原则的规范

    LSP为良好的继承定义了规范:

    • 子类必须完全实现父类的方法
    • 子类可以有自己的个性
    • 覆盖或实现父类的方法时输入参数可以被放大(反协变)(java会将此认作方法重载)
    • 覆盖或实现父类的方法时输出结果可以被缩小(协变)

ISP 接口分离原则(The Interface Segregation cPrinciple)

  1. 两种定义:

    • Clients should not be forced to depend upon interfaces that they don’t use. 客户端不应该依赖它不需用的接口。

    • The dependency of one class to another one should depend on the smallest possible interface。类间的依赖关系应该建立在最小的接口上。

  2. 理解:

    • 建立单一接口 ,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。也就是说,我们要为各个类建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
    • __依赖几个专用的接口__要比依赖一个综合的接口:系统的灵活性更高,可维护性更好
  3. 区别一下单一职责原则和接口分离原则:

    • 单一职责原则注重的是职责;接口隔离原则注重对接口依赖的隔离。
    • 单一职责原则主要是约束类;接口隔离原则主要约束接口

DIP 依赖转置原则(The Dependency Inversion Principle)

  1. 定义:

    • High level modules should not depend upon low level modules,Both should depend upon abstractions.高层模块不应该依赖低层模块,两者都应该依赖抽象
    • Abstractions should not depend upon details.抽象不应该依赖细节
    • Details should depend upon abstracts.细节应该依赖抽象

    在java中,抽象就是接口和抽象类,细节就是实现类,翻译过来就是:

    • 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。

    • 接口或抽象类不依赖实现类

    • 实现类依赖接口或抽象类

    一句话概括就是——“面向接口编程”

  2. 前人经验:

    • 每个类尽量都有接口或者抽象类,或者抽象类和接口两都具备

    • 变量的表面类型尽量是接口或者抽象类

    • 任何类都不应该从具体类派生

    • 尽量不要覆写基类的方法

    • 如果基类是一个抽象类,而这个方法已经实现了,子类尽量不要覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会有一定的影响。

    • 结合里氏替换原则使用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值