为何要有设计模式,其实就是对前人代码经验的一种总结。
七大设计原则包括:开闭原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特法则、里氏替换原则、合成复用原则。
1、开闭原则
- 开闭原则(Open-Closed Principle,OCP)是指一个软件实体(比如类、模块、函数等)对外界扩展开放,对于自身的修改关闭。顾名思义,开闭针对的是扩展和修改两个行为。重点思想是使用抽象构建框架,使用实现扩展细节。这样可以提高系统的可用性和可维护性,使得系统更加灵活。当我们对软件进行版本迭代时,可以不用修改源码,直接在源码基础上扩展。
- 比如我们定义一个IHuman接口
public interface IHuman {
void sing();
void jump();
void rap();
}
- 人有善恶美丑,比如我们创建一个善良的人:
public class GoodPeople implements IHuman{
@Override
public String sing() {
return "我爱唱";
}
@Override
public String jump() {
return "我爱跳";
}
@Override
public String rap() {
return "我爱饶舌";
}
}
- 但是呢,现在有个善良的人他说,我不止爱跳,我还爱蹦跶,那么怎么办呢:
public class GoodHopPeople extends GoodPeople{
@Override
public String sing() {
return super.sing();
}
@Override
public String jump() {
StringBuilder sb = new StringBuilder();
sb.append(super.jump());
sb.append("我也爱蹦跶");
return sb.toString();
}
@Override
public String rap() {
return super.rap();
}
}
2、依赖倒置原则
- 依赖倒置原则(Dependence Inversion Principle,DIP)是指设计代码结构时,高层的模块不能依赖于底层的模块,二者要依赖自己的抽象。同时呢,细节要依赖抽象,抽象不能依赖细节,目的就是提高系统的稳定性,解耦类与类之间的依赖关系
- 比如我们创建一个类GuangTouQiang:
public class GuangTouQiang {
public void KanXiongDaShu() {
System.out.println("去砍熊大的树");
}
public void KanXionErShu() {
System.out.println("去砍熊二的树");
}
}
- 这时候,我们看看老板是怎么让光头强干活的:
public class DoWork {
public static void main(String[] args) {
GuangTouQiang guangTouQiang = new GuangTouQiang();
guangTouQiang.KanXiongDaShu();
guangTouQiang.KanXionErShu();
}
}
- 这时候,老板来电话了,说光头强,先把吉吉国王住的那片树砍了,这时候,如果要添加这个功能,那么需要在GuangTouQiang这个类中添加一个方法去实现老板的命令,还要在DoWork这个高层调用中去修改,这样对系统的影响其实是无法估量的,而且类之间也紧紧地耦合在了一起,那么怎么优化呢:
- 创建一个ITask 接口:
public interface ITask {
String kanSHu();
}
- 老板给的第一个任务:
public class FirstTask implements ITask{
@Override
public void kanSHu() {
System.out.println("砍熊大的树");
}
}
- 老板给的第二个任务:
public class SecondTask implements ITask {
@Override
public void kanSHu() {
System.out.println("砍熊二的树");
}
}
- 老板给的新任务:
public class ThirdTask implements ITask {
@Override
public void kanSHu() {
System.out.println("砍吉吉国王的树");
}
}
- 光头强这时候也需要做一些变化:
public class GuangTouQiang {
public void kanShu(ITask task) {
task.kanSHu();
}
}
- 光头强开始干活:
public class DoWork {
public static void main(String[] args) {
GuangTouQiang guangTouQiang = new GuangTouQiang();
guangTouQiang.kanShu(new FirstTask());
guangTouQiang.kanShu(new SecondTask());
guangTouQiang.kanShu(new ThirdTask());
}
}
- 这时候,我们可以看到,无论老板接下来让光头强砍谁的树,我们只需要新建一个类,实现任务接口,然后以参数的形式传给光头强就行了,而不用修改源代码,这样在实际开发场景中,降低了风险,同时,新任务的实现只依赖于抽象任务接口,光头强也不依赖于任务,只关心自己砍树,至于砍谁的,那就看传来的参数了,实现了任务类和光头强之间的解耦。
3、单一职责原则
- 单一职责原则(Simple Responsibility Principle,SRP)是指不要存在多于一个导致类变更的原因。比如我们有一个类,负责两个功能,如果其中一个功能因需求要做出修改,这时可能会影响另一个功能。这时,这个类就有两个需要变更的原因,解决的办法就是定义两个类,各司其职,两个功能相互解耦,这样就降低了类的复杂度,提高了可维护性。
- 我们的光头强,有时候砍树,有时候休息:
public class GuangTouQiang {
public void dailyLife(String task) {
if("砍树".equals(task)) {
System.out.println("开始干活砍树");
} else {
System.out.println("累了,得休息休息");
}
}
}
- 看下代码调用:
public class LiveLife {
public static void main(String[] args) {
GuangTouQiang guangTouQiang = new GuangTouQiang();
guangTouQiang.dailyLife("砍树");
guangTouQiang.dailyLife("休息");
}
}
- 如果现在老板说,光头强你在砍树的时候顺便给我逮只熊,那这时候就要去修改判断逻辑,而这段逻辑涉及"休息"这一功能,在实际开发中会造成不可控的影响,这时需要对两个功能进行解耦,先定义一个Work类:
public class Work {
public void doWork() {
System.out.println("老板发话了,光头强开始干活");
}
}
- 再定义一个Rest类:
public class Rest {
public void doRest() {
System.out.println("被熊欺负了一天,一棵树没砍到,回家休息了");
}
}
- 这时候看光头强的日常是什么样的:
public class LiveLife {
public static void main(String[] args) {
Work work = new Work();
work.doWork();
System.out.println("-------我是一条分割线-------");
Rest rest = new Rest();
rest.doRest();
}
}
- 工作和休息互不干扰,当其中一个功能需要修改时,对另一个功能没有任何影响,实现了功能之间的解耦。