1. 开闭原则(Open Closed Principle,OCP):当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求。

图1 Windows的桌面主题类图

  1. 里氏替换原则(Liskov Substitution Principle,LSP):子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。

图2 “几维鸟不是鸟”实例的类图(不符合里氏替换原则)

图3 “几维鸟是动物”实例的类图(合里氏替换原则)

  1. 依赖倒置原则(Dependence Inversion Principle,DIP):高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向实现编程。

图4 顾客购物程序的类图

违反依赖倒置原则代码(顾客每更换一家商店,都要修改一次代码,这明显违背了开闭原则。存在以上缺点的原因是:顾客类设计时同具体的商店类绑定了,这违背了依赖倒置原则):

class Customer{
    public void shopping(ShaoguanShop shop){
        //购物
        System.out.println(shop.sell());
    }
}

class Customer{
    public void shopping(WuyuanShop shop){
        //购物
        System.out.println(shop.sell());
    }
}

修改后的符合依赖倒置原则代码(定义“婺源网店”和“韶关网店”的共同接口 Shop,顾客类面向该接口编程,其代码修改如下:):

public class DIPtest{
    public static void main(String[] args){
        Customer wang=new Customer();
        System.out.println("顾客购买以下商品:"); 
        wang.shopping(new ShaoguanShop()); 
        wang.shopping(new WuyuanShop());
    }
}
//商店
interface Shop{
    public String sell(); //卖
}
//韶关网店
class ShaoguanShop implements Shop{
    public String sell(){
        return "韶关土特产:香菇、木耳……"; 
    } 
}
//婺源网店
class WuyuanShop implements Shop{
    public String sell(){
        return "婺源土特产:绿茶、酒糟鱼……"; 
    }
} 
//顾客
class Customer{
    public void shopping(Shop shop){
        //购物
        System.out.println(shop.sell()); 
    }
}
  1. 单一职责原则(Single Responsibility Principle,SRP):单一职责原则规定一个类应该有且仅有一个引起它变化的原因,否则类应该被拆分

图5 大学学生工作管理程序的类图

  1. 接口隔离原则(Interface Segregation Principle,ISP):要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。

图6 学生成绩管理程序的类图

  1. 迪米特法则(Law of Demeter,LoD)又叫作最少知识原则(Least Knowledge Principle,LKP):如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。迪米特法则中的“朋友”是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。

图7 明星与经纪人的关系图

public class LoDtest{
    public static void main(String[] args){
        Agent agent=new Agent();
        agent.setStar(new Star("林心如"));
        agent.setFans(new Fans("粉丝韩丞"));
        agent.setCompany(new Company("中国传媒有限公司"));
        agent.meeting();
        agent.business();
    }
}
//经纪人
class Agent{
    private Star myStar;
    private Fans myFans;
    private Company myCompany;
    public void setStar(Star myStar){
        this.myStar=myStar;
    }
    public void setFans(Fans myFans){
        this.myFans=myFans;
    }
    public void setCompany(Company myCompany){
        this.myCompany=myCompany;
    }
    public void meeting(){
        System.out.println(myFans.getName()+"与明星"+myStar.getName()+"见面了。");
    }
    public void business(){
        System.out.println(myCompany.getName()+"与明星"+myStar.getName()+"洽淡业务。");
    }
}
//明星
class Star{
    private String name;
    Star(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
}
//粉丝
class Fans{
    private String name;
    Fans(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
}
//媒体公司
class Company{
    private String name;
    Company(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
}
  1. 合成复用原则(Composite Reuse Principle,CRP)又叫组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP):它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。

图8 用继承关系实现的汽车分类的类图(不符合合成复用原则)

图9 用组合关系实现的汽车分类的类图(符合合成复用原则)

开闭原则是总纲,它告诉我们要对扩展开放,对修改关闭;里氏替换原则告诉我们不要破坏继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一;接口隔离原则告诉我们在设计接口的时候要精简单一;迪米特法则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用。


汤太咸
3 声望1 粉丝

程序员一枚,也爱读书,也爱理财,还喜欢把学到的读到的总结出来写点东西,写的不难,希望大家喜欢。