软件设计原则

1.开闭原则

    对扩展开放,对修改关闭

/**
* @ClassName: IPatient
* @Description: 病人接口
* @Author: mszhou
* @Date: 2021/6/4 17:05
* @Version: 1.0
**/
public interface IPatient {
    /**
     * 姓名
     * @return
     */
    public String getName();

    /**
     * 服药费用
     * @param medicine
     * @return
     */
     public BigDecimal pay(Medicine medicine);
}


import java.math.BigDecimal;
/**
* @ClassName: Medicine
* @Description: 药品类
* @Author: mszhou
* @Date: 2021/6/4 17:06
* @Version: 1.0
**/
public class Medicine {
    private String name;
    private BigDecimal price;

    public Medicine(String name, BigDecimal price) {
        this.name = name;
        this.price = price;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

import java.math.BigDecimal;
/**
* @ClassName: Hospital
* @Description: 医院类
* @Author: mszhou
* @Date: 2021/6/4 17:12
* @Version: 1.0
**/
public class Hospital {
    private Medicine medicine = new Medicine("阿斯思林",new BigDecimal(20));
    public void  sellMedicine(IPatient patient){
        BigDecimal money = patient.pay(medicine);
        System.out.println(patient.getName()+"花 了"+money.setScale(2,BigDecimal.ROUND_HALF_UP)
        +"块钱买了药:"+medicine.getName());
    }
}

import java.math.BigDecimal;
/**
* @ClassName: OneLevelSocialSecurityPatient
* @Description: TODO
* @Author: mszhou
* @Date: 2021/6/4 17:22
* @Version: 1.0
**/
public class OneLevelSocialSecurityPatient implements IPatient{
    private String name;
    public OneLevelSocialSecurityPatient(String name) {
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public BigDecimal pay(Medicine medicine) {
        return medicine.getPrice().multiply(new BigDecimal(0.7));
    }
}

import java.math.BigDecimal;
/**
* @ClassName: ThreeLevelSocialSecurityPatient
* @Description: TODO
* @Author: mszhou
* @Date: 2021/6/4 17:25
* @Version: 1.0
**/
public class ThreeLevelSocialSecurityPatient implements IPatient{

    private String name;

    public ThreeLevelSocialSecurityPatient(String name) {
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public BigDecimal pay(Medicine medicine) {
        return medicine.getPrice().multiply(new BigDecimal(0.9));
    }
}

import java.math.BigDecimal;
/**
* @ClassName: TwoLevelSocialSecurityPatient
* @Description: TODO
* @Author: mszhou
* @Date: 2021/6/4 17:24
* @Version: 1.0
**/
public class TwoLevelSocialSecurityPatient implements IPatient{
    private String name;
    public TwoLevelSocialSecurityPatient(String name) {
        this.name = name;
    }
    @Override
    public String getName() {
        return name;
    }
    @Override
    public BigDecimal pay(Medicine medicine) {
        return medicine.getPrice().multiply(new BigDecimal(0.7));
    }
}

/**
* @ClassName: OcpTest1
* @Description: 测试类
* @Author: mszhou
* @Date: 2021/6/4 17:27
* @Version: 1.0
**/
public class OcpTest1 {

    public static void main(String[] args) {
        Hospital hospital = new Hospital();
        IPatient xiaohong = new OneLevelSocialSecurityPatient("小红");
        hospital.sellMedicine(xiaohong);
        IPatient xiaoming = new TwoLevelSocialSecurityPatient("小明");
        hospital.sellMedicine(xiaoming);
        IPatient xiaojie = new ThreeLevelSocialSecurityPatient("小杰");
        hospital.sellMedicine(xiaojie);
    }
}

2.依赖倒置原则

    依赖倒置的中心思想是面向接口编程,将上层和下层通过接口隔离开来 ----解耦

软件设计原则

public interface ICourse {    
    void study();
}
public class JavaCourse implements ICourse {    
    @Override    
    public void study() {        
        System.out.println("「灯塔君」同学正在学习「Java」课程");    
    }
}
public class DesignPatternCourse implements ICourse {   
     @Override    
    public void study() {        
        System.out.println("「灯塔君」同学正在学习「设计模式」课程");    
    }
}
public class Wmyskxz {    
    public void study(ICourse course) {       
        course.study();    
    }
}
public class DIPTest {    
    public static void main(String[] args) {        
        Wmyskxz wmyskxz = new Wmyskxz();        
        wmyskxz.study(new JavaCourse());        
        wmyskxz.study(new DesignPatternCourse());    
    }
}

3.单一职责原则

    即一个类/接口/抽象只负责一项职责       案例 :电话这玩意,是现代人都离不了,电话通话的时候有四个过程发生:拨号、通话、回应、挂机,那我们写一个接口,其类图应该如图所示   软件设计原则
public interface IPhone {
    //拨通电话
    public void dial(String phoneNumber);
    //通话
    public void chat(Object o);
    //回应,只有自己说话而没有回应,那算啥?!
    public void answer(Object o);
    //通话完毕,挂电话
    public void huangup();
}
IPhone 这个接口它包含了两个职责:一个是协议管理,一个是数据传送 : diag() 和 huangup() 两个方法实现的是协议管理,分别负责拨号接通和挂机; chat() 和 answer() 是数据的传送,把我们说的话转换成模拟信号或数字信号传递到对方,然后再把对 方传递过来的信号还原成我们听得懂语言。 我们可以这样考虑这个问题: 协议接通的变化会引起这个接口或实现类的变化吗?会的! 数据传送(想想看,电话不仅仅可以通话,还可以上网)的变化会引起这个接口或实现类的变化吗? 也会的! 那就很简单了,这里有两个原因都引起了类的变化,而且这两个职责会相互影响吗: 电话拨号,我只要能接通就成,甭管是电信的还是网通的协议; 电话连接后还关心传递的是什么数据吗?不关心,你要是乐意使用 56K 的小猫传递一个高清的片子, 那也没有问题(顶多有人说你 213 了) 解决方案     通过这样的分析,我们发现类图上的 IPhone 接口包含了两个职责,而且这两个职责的变化不相互影响,那就考虑拆开成两个接口,其类图如图所示。

软件设计原则

这个类图看着有点复杂了,虽然完全满足了单一职责原则的要求,每个接口职责分明,结构清晰,但是我相信你在设计的时候肯定不会采用这种方式,一个手机类要把ConnectionManager和DataTransfer组合在一块才能使用。组合是一种强耦合关系,你和我都有共同的生命期,这样的强耦合关系还不如使用接口实现的方式呢,而且还增加了类的复杂性,多了两个类。经过这样的思考后,我们再修改一下类图,如图所示

软件设计原则

软件设计原则

所以,我们会将接口设计如下:

public interface IConnectionManager {
  //拨通电话
  public void dial(String phoneNumber);
  //通话完毕,挂电话
  public void huangup();
}
public interface IDataTransferManager {
  //通话
  public void chat(Object o);
  //回应,只有自己说话而没有回应,那算啥?!
  public void answer(Object o);
}

这样的话,连接协议的变动和通话数据的传送没有半毛钱关系了,不会相互影响!

4.接口隔离原则

    客户端不应该依赖他不需要的接口,如订单只会实现订单接口,而不会实现用户接口

    类间的依赖关系应该建立在最小的接口上,如只读操作的接口只应该有查询的方法

5.里氏替换原则

        不要破坏继承体系;

    满足规则:

        1.子类必须实现父类的抽象方法,而尽可能不要重写覆盖父类的方法。

        2.子类可以有自己的个性:从里氏替换原则原则来看,就是子类出现的方法父类未必就可以出现

        3.覆盖或实现父类的方法时输入参数可以被放大   ---方法参数子类比父类大

        4.重写或实现父类的方法时输出结果可以被缩小   ---return 类型比父类小,如果比父类大编译不通过

6.合成复用原则

    如果两个类之间不是父子上下级关系,而又需要进行关联完成业务时,应该使用合成复用,而不是继承因为两个对象是平等关系,可以相互依赖,那么这样做就可以实现,而继承不能实现

        1.简单依赖,通过形参传入依赖的对象

        2.通过set注入的形式依赖对象

        3.框架中通过属性注入的形式引入依赖对象

7.迪米特原则

    最少知道原则 如洗衣服,我只要扔进去就不管了,不需要知道他是怎么洗,怎么烘干

    只和直接朋友交谈----不要在局部变量使用陌生类

总结:

    开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭;

    依赖倒置原则告诉我们要面向接口编程;

    单一职责原则告诉我们实现类要职责单一;

    接口隔离原则告诉我们在设计接口的时候要精简单一;

    里氏替换原则告诉我们不要破坏继承体系;

    合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用

    迪米特法则告诉我们要降低耦合度;

 

 

 

 

 

 

上一篇:java.lang.IllegalArgumentException: Comparison method violates its general contract 异常


下一篇:BigDecimal用法详解