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.迪米特原则
最少知道原则 如洗衣服,我只要扔进去就不管了,不需要知道他是怎么洗,怎么烘干
只和直接朋友交谈----不要在局部变量使用陌生类
总结:
开闭原则是总纲,他告诉我们要对扩展开放,对修改关闭;
依赖倒置原则告诉我们要面向接口编程;
单一职责原则告诉我们实现类要职责单一;
接口隔离原则告诉我们在设计接口的时候要精简单一;
里氏替换原则告诉我们不要破坏继承体系;
合成复用原则告诉我们要优先使用组合或者聚合关系复用,少用继承关系复用
迪米特法则告诉我们要降低耦合度;