初探设计模式六大原则
前言
目录
-
单一职责原则
-
里氏替换原则
-
依赖倒置原则
-
接口隔离原则
-
迪米特原则
-
开闭原则
P1.单一职责原则(Single Responsibility Principle)
public class People { public void playCnBlogs () { System.out.println("刷博客"); } public void doSports () { System.out.println("打乒乓球"); } public void work () { System.out.println("工作"); } }
-
刷博客园,这是博主的职责
-
打乒乓球,这是业余运动爱好者的职责
-
工作,这是“普普通通上班族”的职责(似乎暴露了什么)
// 知乎er public interface Blogger { public void playCnBlogs(); } // 上班族 public interface OfficeWorkers { public void work(); } // 业余运动爱好者 public interface AmateurPlayer { public void doSports(); }
public class People implements Blogger,AmateurPlayer,OfficeWorkers{ public void playCnBlogs () { System.out.println("刷博客园"); } public void doSports () { System.out.println("打乒乓球"); } public void work () { System.out.println("工作"); } }
public class Index { public static void main (String args []) { People people = new People(); Blogger blogger = new People(); blogger.playCnBlogs(); // 输出:刷博客园 OfficeWorkers workers = new People(); workers.work(); // 输出: 工作 AmateurPlayer players = new People(); players.doSports(); // 输出:打乒乓球 } }
P2.里氏替换原则(liskov substitution principle)
public abstract class Father { // 认真工作 public abstract void work(); // 其他方法 }
子类
public class Son extends Father { @Override public void work() { // 我实现了爸爸的work方法,旦我什么也不做! } }
子类虽然表面上实现了父类的方法,但是他实际上并没有实现父类要求的逻辑。里氏替换原则要求我们避免这种“塑料父子情”,如果出现子类不得不脱离父类方法范围的情况, 采取其他方式处理,详情参考《设计模式之禅》
P3.依赖倒置原则 (dependence inversion principle)
-
高层的模块不应该依赖于低层的模块,这两者都应该依赖于其抽象
-
抽象不应该依赖细节
-
细节应该依赖抽象
// 底层模块1:开发者 public class Coder { public void develop (Linux linux) { System.out.printf("开发者正在%s系统上进行开发%n",linux.getSystemName()); } } // 底层模块2:Linux操作系统 public class Linux { public String name; public Linux(String name){ this.name = name; } public String getSystemName () { return this.name; } } // 高层模块 public class Index { public static void main (String args []) { Coder coder = new Coder(); Linux ubuntu = new Linux("ubuntu系统"); // ubuntu是一种linux操作系统 coder.develop(ubuntu); } }
开发者正在ubuntu系统系统上进行开发
但是我们能发现其中的问题:
// 程序员接口 public interface Programmer { public void develop (OperatingSystem OS); } // 操作系统接口 public interface OperatingSystem { public String getSystemName (); } // 低层模块:Linux操作系统 public class Linux implements OperatingSystem{ public String name; public Linux (String name) { this.name = name; } @Override public String getSystemName() { return this.name; } } // 低层模块:Window操作系统 public class Window implements OperatingSystem { String name; public Window (String name) { this.name = name; } @Override public String getSystemName() { return this.name; } } // 低层模块:开发者 public class Coder implements Programmer{ @Override public void develop(OperatingSystem OS) { System.out.printf("开发者正在%s系统上进行开发%n",OS.getSystemName()); } } // 高层模块:测试用 public class Index { public static void main (String args []) { Programmer coder = new Coder(); OperatingSystem ubuntu = new Linux("ubuntu系统"); // ubuntu是一种linux操作系统 OperatingSystem windows10 = new Window("windows10系统"); // windows10 coder.develop(ubuntu); coder.develop(windows10); } }
P4. 接口隔离原则(interface segregation principle)
-
接口要足够细化,当然了,这会让接口的数量变多,但是每个接口会具有更加明确的功能
-
在1的前提下,类应该依赖于“最小”的接口上
public interface Blogger { // 认真撰文 public void seriouslyWrite(); // 友好评论 public void friendlyComment(); // 无脑抬杠 public void argue(); // 键盘攻击 public void keyboardAttack (); }
public interface PositiveBlogger { // 认真撰文 public void seriouslyWrite(); // 友好评论 public void friendlyComment(); } public interface NegativeBlogger { // 无脑抬杠 public void argue(); // 键盘攻击 public void keyboardAttack (); }
-
单一职责原则和接口隔离原则虽然看起来有点像,好像都是拆分,但是其实侧重点是不一样的,“职责”的粒度其实是比“隔离接口”的粒度要大的
-
基于1中阐述的原因,其实 单一职责原则 和 接口隔离原则是可能会产生冲突的,因为接口隔离原则要求粒度尽可能要细,但是单一职责原则却不同,它要求拆分既不能过粗,但也不能过细,如果把原本单一职责的接口分成了“两个0.5职责的接口”,那么这就是单一职责所不能允许的了。
-
当两者冲突时,优先遵循 单一职责原则
P5.迪米特原则 (law of demeter)
// 我的直接朋友 public class MyFriend { // 找他的朋友 public void findHisFriend (FriendOfMyFriend fof) { System.out.println("这是朋友的朋友:"+ fof.name); } } // 朋友的朋友,但不是我的朋友 public class FriendOfMyFriend { public String name; public FriendOfMyFriend(String name) { this.name = name; } } // 我 public class Me { public void findFriend (MyFriend myFriend) { System.out.println("我找我朋友"); // 注意这段代码 FriendOfMyFriend fmf = new FriendOfMyFriend("陌生人"); myFriend.findHisFriend(fmf); }; }
-
一个类只和朋友类交流,朋友类指的是出现在成员变量、方法的输入输出参数中的类
-
一个类不和陌生类交流,即没有出现在成员变量、方法的输入输出参数中的类
// 我朋友 public class MyFriend { public void findHisFriend () { FriendOfMyFriend fmf = new FriendOfMyFriend("陌生人"); System.out.println("这是朋友的朋友:"+ fmf.name); } } // 朋友的朋友,但不是我的朋友 public class FriendOfMyFriend { public String name; public FriendOfMyFriend(String name) { this.name = name; } } // 我 public class Me { public void findFriend (MyFriend myFriend) { System.out.println("我找我朋友"); myFriend.findHisFriend(); }; }
P6. 开闭原则(open closed principle)
总结
-
原则不是死板的而是灵活的
-
一些原则其实是存在一定的冲突的,重要的是权衡,是掌握好度
-
六大原则是23种设计模式的灵魂,六大原则指导了设计模式,设计模式体现了六大原则
就像很多人说的,其实设计模式是一种思想,关键的还是怎样和业务结合起来,我也刚学习不久呢,如果前辈们有什么好的见解,还请在评论区指点一下,不胜感激