Java设计模式之七大原则

设计模式作用

  • 代码重用性
  • 可读性
  • 可扩展性
  • 可靠性 (即:当我们增加新的功能后,对原来没有影响 )
  • 使程序呈现 高内聚 ,低耦合

常用七大原则

单一职责原则(Single Responsibility Principle)

  • 参考链接

    https://mp.weixin.qq.com/s/yPcjk-e1aKT_jIDWnW7wqQ

  • 概念
    对类来说的,即一个类应该只负责一项职责

  • 适用范围

    如类A负责两个不同职责:职责1,职责2。 当职责1需求变更而改变A时,可能造成职责2执行错误, 所以需要将类A的粒度分解为 A1,A2

    单一职责原则适用的范围有接口、方法、类。按大家的说法,接口和方法必须保证单一职责,类就不必保证,前提是类中方法数量足够少,可以在方法级别保持单一职责原则

  • 案例代码

接口隔离原则(Interface Segregation Principle)

  • 参考链接

    https://mp.weixin.qq.com/s/g9nVW3WJIfe9f-bu6ZYSAw

  • 概念

    客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上

  • 适用范围

    类A通过接口Interface1依赖类B,类C通过接口Interface1依赖类D,如果接口Interface1对于类A和类C来说都不是最小接口,那么类B和类D必须去实现他们不需要的方法

    将接口Interface1拆分独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。

  • 案例代码

依赖倒置原则(Dependence Inversion Principle)

  • 参考链接

    https://mp.weixin.qq.com/s/fb9X_HN7Gb_xj0JAh2Do9w

  • 概念

    1. 高层模块不应该依赖低层模块,两者都应该依赖其抽象(模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的)

    2. 抽象不应该依赖细节(接口或抽象类不依赖于实现类)

    3. 细节应该依赖抽象(实现类依赖接口或抽象类)

    4. 依赖倒置的中心思想是面向接口编程

    5. 使用接口或抽象类的目的一是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成

  • 适用范围

    Spring框架中的DI(依赖注入)思想

  • 依赖传递方式

    1. 接口传递

      
          interface IOpenAndClose {//开关的接口
              public void open(ITV tv); //抽象方法,接收接口
          }
      
          interface ITV { //ITV接口
              public void play();
          }
      
          class ChangHong implements ITV {
      
              @Override
              public void play() {
                  // TODO Auto-generated method stub
                  System.out.println("长虹电视机,打开");
              }
      
          }
          // 实现接口
          class OpenAndClose implements IOpenAndClose{
              public void open(ITV tv){
                  tv.play();
              }
          }
      
      
    2. 构造方法传递

      
          interface IOpenAndClose {
              public void open(); //抽象方法
          }
      
          interface ITV { //ITV接口
              public void play();
          }
      
          class OpenAndClose implements IOpenAndClose{
          
              public ITV tv; //成员
              public OpenAndClose(ITV tv){ //构造器
                  this.tv = tv;
              }
              public void open(){
                  this.tv.play();
              }
          }
      
      
    3. setter方式传递

      
          interface IOpenAndClose {
              public void open(); // 抽象方法
      
              public void setTv(ITV tv);
          }
      
          interface ITV { // ITV接口
              public void play();
          }
      
          class OpenAndClose implements IOpenAndClose {
              private ITV tv;
      
              public void setTv(ITV tv) {
                  this.tv = tv;
              }
      
              public void open() {
                  this.tv.play();
              }
          }
      
          class ChangHong implements ITV {
      
              @Override
              public void play() {
                  // TODO Auto-generated method stub
                  System.out.println("长虹电视机,打开");
              }
              
          }
      
      
      
      
  • 案例代码

    1. 老板抽象类及类

          public abstract class Boss {
      
              private Staff staff;
      
              public Boss(Staff staff) {
                  this.staff = staff;
              }
      
              public abstract void support();
      
              public abstract void askHelp(Boss boss);
      
              public Staff getStaff() {
                  return staff;
              }
      
              public void setStaff(Staff staff) {
                  this.staff = staff;
              }
          }
         
      
          public class BossImpl extends Boss {
      
              public BossImpl(Staff staff) {
                  super(staff);
              }
      
              @Override
              public void support() {
                  this.getStaff().service();
              }
      
              @Override
              public void askHelp(Boss boss) {
                  boss.support();
              }
          }
      
      
      
      
    2. 员工抽象类及类

      
           public abstract class Staff {
      
              private String name;
      
              public abstract void service();
      
              public abstract void askHelp(Boss boss);
      
              public String getName() {
                  return name;
              }
      
              public void setName(String name) {
                  this.name = name;
              }
          }
      
      
          public class StaffImpl extends Staff{
      
              public StaffImpl(String name) {
                  this.setName(name);
              }
      
              @Override
              public void service() {
      
                  System.out.println(this.getName() + "提供服务");
              }
      
              @Override
              public void askHelp(Boss boss) {
                  boss.support();
              }
          }
      
      
    3. 测试方法

      
          public class DependenceInversionTest {
      
              public static void main(String[] args) {
                  Staff staffA = new StaffImpl("A员工");
                  Staff staffB = new StaffImpl("B员工");
      
                  Boss bossA = new BossImpl(staffA);
                  Boss bossB = new BossImpl(staffA);
      
                  //A老板向B老板求助
                  bossA.askHelp(bossB);
      
                  //B员工向A老板求支援
                  staffB.askHelp(bossA);
      
                  //A老板辞退了A员工,换成了C员工
                  Staff staffC = new StaffImpl("C员工");
                  bossA.setStaff(staffC);
      
                  //B员工向A老板求支援
                  staffB.askHelp(bossA);
              }
          }
      
      
      
  • 注意事项

    1. 低层模块尽量都要有抽象类或接口,或两者都有,程序稳定性更好

    2. 变量都声明类型尽量是抽象类或接口,这样变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化

    3. 继承时遵循里式替换原则

里式替换原则(Liskov Substitution Principle)

  • 参考链接

    https://mp.weixin.qq.com/s/qjkPRhYWBEax8A59wZY3Lw

  • 概念

    1. 如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。(假如 A 能胜任 B 干的所有事情,那 B 就是 A 的父亲,也就是儿子要会父亲的所有能活,儿子活得再烂也要有父亲的水平。)

    2. 所有引用基类的地方必须能透明地使用其子类的对象

  • 适用范围

    当需要重新父类(抽象类)原有非抽象方法时,将原来的父类和子类都继承一个更通俗的基类,原有的继承关系去掉,采用依赖、聚合、组合等关替代

  • 案例代码

  • 注意事项

    1. 在使用继承时,遵循里式替换原则,在子类中尽量不要重写父类方法

    2. 里式替换原则中,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合、组合、依赖来解决问题

开闭原则ocp(Open Closed Principle)

  • 参考链接
    https://mp.weixin.qq.com/s/szBP4A1TFQL1RVZvXEknRA

  • 概念

    软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的

  • 适用范围

    编程中遵循其他原则,以及使用设计模式的目的就是遵循开闭原则

  • 案例代码

    1. 改造前

      
          public class Ocp {
      
              public static void main(String[] args) {
                  //使用看看存在的问题
                  GraphicEditor graphicEditor = new GraphicEditor();
                  graphicEditor.drawShape(new Rectangle());
                  graphicEditor.drawShape(new Circle());
                  graphicEditor.drawShape(new Triangle());
              }
      
          }
      
          //这是一个用于绘图的类 [使用方]
          class GraphicEditor {
              //接收Shape对象,然后根据type,来绘制不同的图形
              public void drawShape(Shape s) {
                  if (s.m_type == 1)
                      drawRectangle(s);
                  else if (s.m_type == 2)
                      drawCircle(s);
                  else if (s.m_type == 3)
                      drawTriangle(s);
              }
      
              //绘制矩形
              public void drawRectangle(Shape r) {
                  System.out.println(" 绘制矩形 ");
              }
      
              //绘制圆形
              public void drawCircle(Shape r) {
                  System.out.println(" 绘制圆形 ");
              }
              
              //绘制三角形
              public void drawTriangle(Shape r) {
                  System.out.println(" 绘制三角形 ");
              }
          }
      
          //Shape类,基类
          class Shape {
              int m_type;
          }
      
          class Rectangle extends Shape {
              Rectangle() {
                  super.m_type = 1;
              }
          }
      
          class Circle extends Shape {
              Circle() {
                  super.m_type = 2;
              }
          }
      
          //新增画三角形
          class Triangle extends Shape {
              Triangle() {
                  super.m_type = 3;
              }
          }
      
      
      
      
      
    2. 改造后

          //改进思路:把创建Shape类做成抽象类,并提供了一个抽象的draw方法,让子类去实现即可,当有新的图形种类时,只需要让新的图形类继承Shape,并实现darw方法即可,使用方的代码不需要修改
          public class Ocp {
      
              public static void main(String[] args) {
                  //使用看看存在的问题
                  GraphicEditor graphicEditor = new GraphicEditor();
                  graphicEditor.drawShape(new Rectangle());
                  graphicEditor.drawShape(new Circle());
                  graphicEditor.drawShape(new Triangle());
                  graphicEditor.drawShape(new OtherGraphic());
              }
      
          }
      
          //这是一个用于绘图的类 [使用方]
          class GraphicEditor {
              //接收Shape对象,调用draw方法
              public void drawShape(Shape s) {
                  s.draw();
              }
      
              
          }
      
          //Shape类,基类
          abstract class Shape {
              int m_type;
              
              public abstract void draw();//抽象方法
          }
      
          class Rectangle extends Shape {
              Rectangle() {
                  super.m_type = 1;
              }
      
              @Override
              public void draw() {
                  // TODO Auto-generated method stub
                  System.out.println(" 绘制矩形 ");
              }
          }
      
          class Circle extends Shape {
              Circle() {
                  super.m_type = 2;
              }
              @Override
              public void draw() {
                  // TODO Auto-generated method stub
                  System.out.println(" 绘制圆形 ");
              }
          }
      
          //新增画三角形
          class Triangle extends Shape {
              Triangle() {
                  super.m_type = 3;
              }
              @Override
              public void draw() {
                  // TODO Auto-generated method stub
                  System.out.println(" 绘制三角形 ");
              }
          }
      
          //新增一个图形
          class OtherGraphic extends Shape {
              OtherGraphic() {
                  super.m_type = 4;
              }
      
              @Override
              public void draw() {
                  // TODO Auto-generated method stub
                  System.out.println(" 绘制其它图形 ");
              }
          }
      
      
      

迪米特法则(Law of Demeter)

  • 参考链接

    https://mp.weixin.qq.com/s/Dxhdzfvfv0mI1_lDhrG8kw

  • 概念

    1. 每个单元对于其他的单元只能拥有有限的知识:只是与当前单元紧密联系的单元

    2. 每个单元只能和它的朋友交谈:不能和陌生单元交谈

    3. 只和自己直接的朋友交谈

  • 适用范围

    每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式:依赖、关联、组合、聚合等。其中。我们称出现在成员变量,方法参数,方法返回值中的类为直接朋友,而出现在局部变量中的类不是直接朋友。

  • 案例代码

    
        //客户端
        public class Demeter1 {
    
            public static void main(String[] args) {
                System.out.println("~~~使用迪米特法则的改进~~~");
                //创建了一个 SchoolManager 对象
                SchoolManager schoolManager = new SchoolManager();
                //输出学院的员工id 和  学校总部的员工信息
                schoolManager.printAllEmployee(new CollegeManager());
    
            }
    
        }
    
    
        //学校总部员工类
        class Employee {
            private String id;
    
            public void setId(String id) {
                this.id = id;
            }
    
            public String getId() {
                return id;
            }
        }
    
    
        //学院的员工类
        class CollegeEmployee {
            private String id;
    
            public void setId(String id) {
                this.id = id;
            }
    
            public String getId() {
                return id;
            }
        }
    
    
        //管理学院员工的管理类
        class CollegeManager {
            //返回学院的所有员工
            public List<CollegeEmployee> getAllEmployee() {
                List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
                for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
                    CollegeEmployee emp = new CollegeEmployee();
                    emp.setId("学院员工id= " + i);
                    list.add(emp);
                }
                return list;
            }
            
            //输出学院员工的信息
            public void printEmployee() {
                //获取到学院员工
                List<CollegeEmployee> list1 = getAllEmployee();
                System.out.println("------------学院员工------------");
                for (CollegeEmployee e : list1) {
                    System.out.println(e.getId());
                }
            }
        }
    
        //学校管理类
    
        //分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
        //CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则 
        class SchoolManager {
            //返回学校总部的员工
            public List<Employee> getAllEmployee() {
                List<Employee> list = new ArrayList<Employee>();
                
                for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
                    Employee emp = new Employee();
                    emp.setId("学校总部员工id= " + i);
                    list.add(emp);
                }
                return list;
            }
    
            //该方法完成输出学校总部和学院员工信息(id)
            void printAllEmployee(CollegeManager sub) {
                
                //分析问题-改进地方
                //1. 将输出学院的员工方法,封装到CollegeManager
                sub.printEmployee();
            
                //获取到学校总部员工
                List<Employee> list2 = this.getAllEmployee();
                System.out.println("------------学校总部员工------------");
                for (Employee e : list2) {
                    System.out.println(e.getId());
                }
            }
        }
    
    
  • 注意事项

    迪米特法则的核心是降低类之间的耦合,并不是要求完全没有依赖关系

合成复用原则(Composite Reuse Principle)

  • 参考链接

    https://blog.csdn.net/u012361379/article/details/88605867

  • 概念

    原则是尽量使用合成/聚合的方式,而不是使用继承

    继承是is-A,聚合是has-A

  • 适用范围

    当B类要使用A类的方法,尽量选用聚合方式解耦

    B类使用A类方法

  • 其他

    合成表示一种强的拥有关系,体现了严格的部分和整体的关系,部分和整体的生命周期一样,打个比方:人有两个胳膊,胳膊和人就是部分和整体的关系,人去世了,那么胳膊也就没用了,也就是说胳膊和人的生命周期是相同的

    聚合表示一种弱的拥有关系,体现的是A对象可以包含B对象,但是B对象并不是A对象的一部分,打个比方:人是群居动物,所以每个人属于一个人群,一个人群可以有多个人,所以人群和人是聚合的关系

总结

  • 核心思想

    1. 找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起

    2. 针对接口编程,而不是针对实现编程

    3. 为了交互对象之间的松耦合设计而努力

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值