设计模式七大原则

1、单一职责原则

1.1 什么是单一职责原则

简单来讲,对于类来说,一个类应该只负责一项职责。如果类A负责两个不同的职责:职责1和职责2。当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1和A2。

举例说明:一个交通工具类,他启动的方式有多种,可以天上飞,可以水里游,可以地上跑。可是一般来说,一个交通工具他启动的方式只有一种(排除特殊的交通工具),那么这个时候,我们就要将这个交通工具类进行拆解成具体的工具

1.2 代码演示

方式一:

class Vehicle{
    public void run(String vehicle){
       System.out.println(vehicle+"在公路上运行");
    }
}

方式一违反了单一职责原则,并不是所有的交通工具都在陆地上运行,这时候我们可以将这个类进行拆分

方式二:

class RoadVehicle{
    public void run(String vehicle){
       System.out.println(vehicle+"在公路上运行");
    }
}

class AirVehicle{
    public void run(String vehicle){
       System.out.println(vehicle+"在天空上运行");
    }
}

class WaterVehicle{
    public void run(String vehicle){
       System.out.println(vehicle+"在水上运行");
    }
}

遵守了单一职责原则,不过改动很大

方式三:

class Vehicle{
    public void runRoad(){
       System.out.println("在公路上运行");
    }

   public void runAir(){
       System.out.println("在天空上运行");
    }

   public void runWater(){
       System.out.println("在海上运行");
    }

}

这种方式没有对类做太大的修改,只是增加方法,虽然没有在类级别上遵守单一职责原则,但是在方法级别上,依然是遵守单一职责原则的

1.3 单一职责原则注意事项

1、降低类的复杂度,一个类只负责一项职责
2、提高类的可读性,可维护性
3、降低变更引起的风险
4、通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级别违反单一职责原则,只有类中的方法数量足够少,可以在方法级别上保持单一职责

2、接口隔离原则

客户端不应该依赖它不需要的接口,即一个类对于另一个类的依赖应该建立在最小的接口上,画图说明
在这里插入图片描述
从上面用例图可以看出来,类A和类B分别只用到了接口当中的部分方法,而我们实现的时候却要实现所有的方法,也就是说此接口对于类A和类C来说并不是最小接口。那么按照接口隔离原则,我们应该做如下的拆分
在这里插入图片描述

3、依赖倒置原则

3.1 依赖倒置介绍

1、高层模块不应该依赖于低层模块,二者应该依赖抽象
2、抽象不应该依赖细节,细节应该依赖抽象
3、依赖倒置的中心思想是面向接口编程
4、依赖倒置设计理念:相对于细节的多边性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础搭建的架构要稳定的多
5、使用接口和抽象类的目的是制定好规范,而不涉及任何操作,把细节的任务交给他们的实现类去完成

3.2 代码演示

需求:Person接收信息

方案一:

class Email{
   pubic String getInfo(){
     return "email:hello";
   }
}

class Person{
   public void receive(Email email){
      System.out.println(email.getInfo());
   }
}

这种方式比较简单,但先在我们还想获取微信,短信等信息时,不仅要新增类还要增加Person中对应的接收方法。

方式二:

interface IReceiver(){
    public String getInfo();
}

class Email implements IReceiver(){
   public String getInfo(){
      return "email:hello";
   }
}

class WeChat implements IReceiver(){
   public String getInfo(){
      return "weChat:hello";
   }
}

class Person{
   public void receive(IReceiver receiver){
     System.out.println(receiver.getInfo());
   }
}

3.3 依赖倒置原则注意事项

1、低层模块尽量要有抽象类或者接口,或者两者都有,程序的稳定性会更好
2、变量的声明尽量是抽象类和接口,这样我们的变量引用和实际对象,就存在一个缓冲层,有利于程序扩展和优化

4、里氏替换原则

在使用继承时,我们应当遵循里氏替换原则,在子类中尽量不要重写父类的方法,继承实际上让两个类耦合性增强了,在适当情况下,可以通过聚合、组合来解决问题

4.1 代码演示

class A{
   //返回两个数的差
   public int function(int num1,int num2){
       return num1-num2;
   }
}

class B extends A{
   //重写A中的方法,把减法改成加法
   public int function(int num1,int num2){
       return num1+num2
   }
}

这个时候要调用A中的方法只能通过Super关键字来调用了。如果遵从里氏替换原则,该怎么写

class Base{
    //将更加基础的方法和属性写到Base类
}

class A extends Base{
   public int function(int num1,int num2){
      return num1-num2;
   }
}

class B extends Base{
  private A a=new A();
   
   public int function(int num1,int num2){
      return num1+num2;
   }
}

这个时候我们想在类B中调用A中的减法,可以通过对象名.方法名来调用了

5、开闭原则

一个软件当中的实体,如类,模块和函数应该对扩展开放,对修改关闭

用代码来演示一下,先看用例图,未遵从开闭原则
在这里插入图片描述

//基类
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;
   }
}
//绘图的类
class GraphEditor{
    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(){
       System.out.println(“绘制矩形”);
    }

    public void drawCircle(){
       System.out.println(“绘制圆”);
    }
    public void drawTriangle(){
       System.out.println(“绘制三角形”);
    }
}

此方式存在的问题是,当我们要新增加一个图形时,要修改GraphEditor类。再来看看下面这种方式
在这里插入图片描述

abstract class Shape{
  int m_type;
  public abstract void draw();
}

class Rectangle extends Shape{
   Rectangle(){
     super.m_type=1;
   }
   public void draw(){
     System.out.println("绘制矩形")
   }
}

class Circle extends Shape{
   Circle(){
     super.m_type=1;
   }
   public void draw(){
     System.out.println("绘制圆")
   }
}

class Triangle extends Shape{
   Triangle(){
     super.m_type=1;
   }
   public void draw(){
     System.out.println("绘制三角形")
   }
}
//绘图的类
class GraphEditor{
   public void drawShape(Shape s){
      s.draw();
   }
}

采用这种方式,我们再新增一个图形,不影响原来的GraphEditor

6、迪米特法则

1、一个对象应该与其他的对象保持最少的了解,类与类关系越密切,耦合度就越大。
2、迪米特法则又称为最小知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂, 都应该逻辑的封装在内部。除了对外提供的public 方法,不泄露任何信息
3、只与直接朋友通信
4、迪米特法则的核心是降低类之间的耦合

需求分析:有一个学校,有各个学院和总部,要求打印学校总部的id和学院员工的id

//学校总部员工类
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<>();
      for(int i=0;i<10;i++){
         CollegeEmployee emp=new CollegeEmployee();
         emp.setId("学院员工id"+i);
         list.add(emp);
      }
      return list;
   }
}

//学校管理类
class SchoolManager{
   //返回学院所有的员工
   public List<Employee> getAllEmployee(){
      List<Employee> list=new ArrayList<>();
      for(int i=0;i<10;i++){
         Employee emp=new Employee();
         emp.setId("学院员工id"+i);
         list.add(emp);
      }
      return list;
   }

    void printAllEmployee(CollegeManager sub){
        //....
        //这里CollegeEmployee不是SchoolManaget的直接朋友,违反了迪米特法则
       List<CollegeEmployee> list= sub.getAllEmployee();
       //打印
    }
}


如果要遵循迪米特法则,则需要将打印的方法,封装在CollegeManaget里

7、合成复用

原则上尽量使用组合或者聚合的方式,而不是使用继承,这个和里氏替换原则有点像,所以很多书上都写的是设计模式六大原则,了解即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值