设计模式之七大原则
1.单一职责原则:
- 不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责
- 使用一个列子来表达,一个动物类,动物可以使用里面的方法进行奔跑:
//单一职责原则测试 public class SingleResponsibility { //举个列子 public static void main(String[] args) { new Animal().run("老虎"); new Animal().run("狮子");
//麻雀为什么能奔跑 错误 new Animal().run("麻雀"); } } //动物 class Animal{ //跑 public void run(String name){ System.out.println(name+"森里里面奔跑"); } }
结果:
- 老虎森里里面奔跑
- 狮子森里里面奔跑
- 麻雀森里里面奔跑
利用单一职责原则来设计:
//单一职责原则测试 public class SingleResponsibility { //举个列子 public static void main(String[] args) { new LandAnimal().run("老虎"); new LandAnimal().run("狮子"); new FlightAnimal().run("麻雀"); } } //陆地动物 class LandAnimal{ //跑 public void run(String name){ System.out.println(name+"森里里面奔跑"); } } //飞行动物 class FlightAnimal{ //飞 public void run(String name){ System.out.println(name+"在天空飞翔"); } }
结果:
- 老虎森里里面奔跑
- 狮子森里里面奔跑
- 麻雀在天空飞翔
2.接口隔离原则:
- 一个类对另一个类的依赖应该建立在最小的接口上。
- 举个列子,水果店和蔬菜店(没有使用之前)
package com.jie.sixprinciples; //接口单一原则 public class SinglePrinciple { public static void main(String[] args) { new FruitStore().cutApple(new LiMaster()); new FruitStore().cutTomato(new LiMaster()); new VegetableShop().cutTomato(new LiuMaster()); new VegetableShop().cutCabbage(new LiuMaster()); } } //切菜接口 interface ChoppingVegetables{ //切苹果 void cutApple(); //切番茄 void cutTomato(); //切白菜 void cutCabbage(); } //李师傅负责水果店 class LiMaster implements ChoppingVegetables{ @Override public void cutApple() { System.out.println("李师傅切苹果"); } @Override public void cutTomato() { System.out.println("李师傅切番茄"); } @Override public void cutCabbage() { System.out.println("李师傅切白菜"); } } class LiuMaster implements ChoppingVegetables{ @Override public void cutApple() { System.out.println("刘师傅切苹果"); } @Override public void cutTomato() { System.out.println("刘师傅切番茄"); } @Override public void cutCabbage() { System.out.println("刘师傅切白菜"); } } //水果店 class FruitStore{ public void cutApple(LiMaster liMaster) { liMaster.cutApple(); } public void cutTomato(LiMaster liMaster) { liMaster.cutTomato(); } public void cutCabbage(LiMaster liMaster) { liMaster.cutCabbage(); } } //蔬菜店 class VegetableShop{ public void cutApple(LiuMaster master) { master.cutApple(); } public void cutTomato(LiuMaster master) { master.cutTomato(); } public void cutCabbage(LiuMaster master) { master.cutCabbage(); } }
结果:
- 李师傅切苹果
- 李师傅切番茄
- 刘师傅切番茄
- 刘师傅切白菜
使用接口隔离原则后:
package com.jie.sixprinciples; //接口单一原则 public class SinglePrinciple { public static void main(String[] args) { new FruitStore().cutApple(new LiMaster()); new FruitStore().cutTomato(new LiMaster()); new VegetableShop().cutTomato(new LiuMaster()); new VegetableShop().cutCabbage(new LiuMaster()); } } //切菜接口 //切苹果 interface CutApple{ //切苹果 void cutApple(); } //切番茄 interface CutTomato{ //切番茄 void cutTomato(); } //切白菜 interface CutCabbage{ //切白菜 void cutCabbage(); } //李师傅负责水果店 class LiMaster implements CutApple,CutTomato{ @Override public void cutApple() { System.out.println("李师傅切苹果"); } @Override public void cutTomato() { System.out.println("李师傅切番茄"); } } class LiuMaster implements CutTomato,CutCabbage{ @Override public void cutTomato() { System.out.println("刘师傅切番茄"); } @Override public void cutCabbage() { System.out.println("刘师傅切白菜"); } } //水果店 class FruitStore{ public void cutApple(LiMaster liMaster) { liMaster.cutApple(); } public void cutTomato(LiMaster liMaster) { liMaster.cutTomato(); } } //蔬菜店 class VegetableShop{ public void cutTomato(LiuMaster master) { master.cutTomato(); } public void cutCabbage(LiuMaster master) { master.cutCabbage(); } }
3.依赖倒转原则:
- 高层模块不应该依赖低层模块,两者都应该依赖其抽象
- 抽象不应该依赖细节,细节应该依赖抽象
- 要面向接口编程,不要面向实现编程
- 举个列子:给QQ发消息:
//依赖倒转列子 没有使用依赖倒置会显得很臃肿 如果想加一个微信 则还需要自动扩展方法等 public class RelyReverse { public static void main(String[] args) { new Message().chat(new Chatqq()); } } //QQ class Chatqq{ //聊天方法 public void chat(){ System.out.println("qq在聊天"); } } //消息类 class Message{ public void chat(Chatqq qq){ qq.chat(); } }
输出: qq在聊天
使用依赖倒转后:
//依赖倒转列子 public class RelyReverse { public static void main(String[] args) { new Message().chat(new Chatqq()); new Message().chat(new ChatWechat()); } } //定义一个接口方法 interface IMessage{ void chat(); } //QQ class Chatqq implements IMessage{ //聊天方法 @Override public void chat(){ System.out.println("qq在聊天"); } } //微信 class ChatWechat implements IMessage{ @Override public void chat() { System.out.println("微信在聊天"); } } //消息类 class Message{ public void chat(IMessage iMessage){ iMessage.chat(); } }
输出:
qq在聊天
微信在聊天
使用依赖倒转三种传递方式:
- 接口传递:
//通过接口来传递 interface InMessage{ void getMessage(Produce produce); } //生产者 interface Produce{ void getMessage(); } class MessageTest implements InMessage{ @Override public void getMessage(Produce produce) { produce.getMessage(); } }
- 通过构造器来进行传递:
//通过构造器来传递 interface InMessage{ void getMessage(); } interface Produce{ void getMessage(); } class MessageTest implements InMessage{ public Produce produce; public MessageTest(Produce produce){ this.produce=produce; } @Override public void getMessage() { this.produce.getMessage(); } }
- 通过set方法来进行:
//通过set()方法来传递 interface InMessage{ void getMessage(); } interface Produce{ void getMessage(); } class MessageTest implements InMessage{ public Produce produce; public void setProduce(Produce produce){ this.produce=produce; } @Override public void getMessage() { this.produce.getMessage(); } }
4.里氏替换原则:
- 子类可以扩展父类的功能,但不能改变父类原有的功能
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
- 子类中可以增加自己特有的方法
- 举一个列子:计算器的加减:
-
//里氏替换原则 public class Replace { public static void main(String[] args) { int add = new Caculator().add(5, 2); System.out.println("计算机加为"+add); int delect = new ChildCaculator().delect(5, 3); //应该为92 为什么为82 因为子类无意间扩展父类方法时破坏了方法需求 System.out.println("扩展的减为"+delect); } } //计算器 加减功能 class Caculator{ public int add(int a,int b){ return a+b; } //减 public int delect(int a,int b){ return a-b; } } //加强版 class ChildCaculator extends Caculator{ //扩展 a+b后继续加10、 public int add(int a,int b){ return a+b+10; } //减与100求差 public int delect(int a,int b){ int add = add(a, b); return add-100; } }
使用里氏替换原则:
-
class Fater{ } //计算器 加减功能 class Caculator extends Fater{ public int add(int a,int b){ return a+b; } //减 public int delect(int a,int b){ return a-b; } } //加强版 class ChildCaculator extends Fater{ //使用属性的方式来调用 private Caculator caculator=new Caculator(); //扩展 a+b后继续加10、 public int add(int a,int b){ return a+b+10; } //减与100求差 public int delect(int a,int b){ int add = caculator.add(a, b); return add-100; } }
5.开闭原则:
- 对扩展开发,对修改关闭
- 如果软件需要改变功能应该是扩展而不是修改
- 列子:绘制图形:
//开闭原则 public class OcpDemo { public static void main(String[] args) { new Grapi().draw(new Round()); new Grapi().draw(new Square()); } } //绘制类 class Grapi{ public void draw(Shape s){ if (s.shapes==1){ round(s); }else if (s.shapes==2){ squar(s); } } //圆形 public void round(Shape s){ System.out.println("正在绘制圆形"); } //绘制正方形 public void squar(Shape s){ System.out.println("正在绘制正方形"); } } //形状类 class Shape{ int shapes; } //圆形 class Round extends Shape{ public Round() { super.shapes=1; } } //正方形 class Square extends Shape{ public Square() { super.shapes=2; } }
6.迪米特法则:
- 一个对象应该对其他对象保持最少的了解
- 类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大。
- 举个例子:总部和学院的人员:
package com.jie.sixprinciples; import java.util.ArrayList; import java.util.List; public class DiMiTieDome { public static void main(String[] args) { new WordHeadQuartersTest().list(new WordPersonTest()); } } //学院员工 class WordPerson { public String getId() { return id; } public void setId(String id) { this.id = id; } private String id; } //总部员工 class WordHeadQuarters { private String id; public String getId() { return id; } public void setId(String id) { this.id = id; } } //总部学院管理类 class WordHeadQuartersTest{ //存10个 public List<WordHeadQuarters> add(){ ArrayList<WordHeadQuarters> wordHeadQuarters = new ArrayList<>(); for (int i = 0; i < 10; i++) { WordHeadQuarters wordHeadQuarters1 = new WordHeadQuarters(); wordHeadQuarters1.setId("总部第"+i+"号人员"); wordHeadQuarters.add(wordHeadQuarters1); } return wordHeadQuarters; } public void list(WordPersonTest wordPersonTest){ for (WordHeadQuarters wordHeadQuarters : this.add()) { System.out.println(wordHeadQuarters.getId()); } System.out.println("........"); for (WordPerson wordPerson : wordPersonTest.add()) { System.out.println(wordPerson.getId()); } } } //学院管理类 class WordPersonTest{ //存10个 public List<WordPerson> add(){ ArrayList<WordPerson> people = new ArrayList<>(); for (int i = 0; i < 10; i++) { WordPerson wordHeadQuarters1 = new WordPerson(); wordHeadQuarters1.setId("学院第"+i+"号人员"); people.add(wordHeadQuarters1); } return people; } }
使用迪米特法则后:降低类之间的关系
-
//总部学院管理类 class WordHeadQuartersTest{ //存10个 public List<WordHeadQuarters> add(){ ArrayList<WordHeadQuarters> wordHeadQuarters = new ArrayList<>(); for (int i = 1; i < 10; i++) { WordHeadQuarters wordHeadQuarters1 = new WordHeadQuarters(); wordHeadQuarters1.setId("总部第"+i+"号人员"); wordHeadQuarters.add(wordHeadQuarters1); } return wordHeadQuarters; } public void list(WordPersonTest wordPersonTest){ for (WordHeadQuarters wordHeadQuarters : this.add()) { System.out.println(wordHeadQuarters.getId()); } System.out.println("........"); wordPersonTest.list(); } } //学院管理类 class WordPersonTest{ //存10个 public List<WordPerson> add(){ ArrayList<WordPerson> people = new ArrayList<>(); for (int i = 1; i < 10; i++) { WordPerson wordHeadQuarters1 = new WordPerson(); wordHeadQuarters1.setId("学院第"+i+"号人员"); people.add(wordHeadQuarters1); } return people; } public void list(){ for (WordPerson wordPerson : this.add()) { System.out.println(wordPerson.getId()); } } }
7.合成复用原则(Interface Segregation Principle,ISP)
-
它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。
- 合成复用原则是通过将已有的对象纳入新对象中,作为新对象的成员对象来实现的,新对象可以调用已有对象的功能,从而达到复用。
- 如果要使用继承关系,则必须严格遵循里氏替换原则。