java 七大设计原则之迪米特原则,开闭原则,合成复用原则(文字代码相结合理解)

java 七大设计原则之迪米特原则,开闭原则,合成复用原则
---文字代码相结合理解

七大设计原则有哪些?

  • 单一职责原则
  • 接口隔离原则
  • 依赖倒转(倒置)原则
  • 里氏替换原则
  • 开闭原则
  • 迪米特法则
  • 合成复用原则

通常大家理解的是前六个,并没有合成复用原则

为什么要使用七大设计原则?

  • 代码重用性(相同的代码不用多次编写);
  • 可读性(编程的规范性,便于其他程序员的阅读和理解);
  • 可拓展性(当需要添加新的功能时,非常的方便也称为可维护性);
  • 可靠性(当我们添加新的功能后对原来的功能没有影响);
  • 使程序呈现高内聚,低耦合等特性

迪米特原则

迪米特原则定义:

  • 一个对象应该对其他对象保持最少的了解
  • 类与类的关系越密切,耦合度越大
  • 迪米特法则还有个更简单的定义:只与直接朋友通信

迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好,也就是说,对于被依赖的类不管多复杂,都尽量将逻辑封装在类的内部,对外提供public方法,不对外泄露信息

什么是直接朋友:

在一个类中:全局变量,返回值,参数传递就称之为直接朋友,

局部变量就称之为陌生朋友

来看一段通俗易懂的代码:

public class A {
    
    }
public class B {
    
    }
public class C {
    
    }
public class D {
    
    }
public class E {
    
    }

public class B {
    
    
   public A mA;

   public C getC(){
    
    
       return null;
   }

   public void showD(){
    
    
       D d = new D();
   }

   public void setA(E e){
    
    

   }
}

在B类中:

  • public A mA; 全局变量
  • public C getC(){ 返回值
    return null;
    }
  • public void showD(){ 局部变量(违反迪米特原则)
    D d = new D();
    }
  • public void setA(E e){} 参数传递

在这里A,C,E就是B的直接朋友,D就是B的陌生朋友

未遵守迪米特原则代码:

public class Student{
    
    
    String name = "";
    public Student(String name) {
    
    
        this.name = name;
    }
}

public class StudentManager {
    
    
    public void getStudentNumber(Student student){
    
    
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
    
    
            list.add(student.name+i);
            Log.i("dimiter:","现在是第 "+i+"个学生,名字为: "+list.get(i));
        }
        Log.i("dimiter:","总共有 "+list.size()+"个学生 ");
    }
}

//使用代码:
//迪米特原则
StudentManager studentManager = new StudentManager();
studentManager.getStudentNumber(new Student("张三"));

分析:

  • 学生类(Student) 有neme参数(学生姓名)
  • 学生管理类(StudentManager)创建10个学生,并输出学生名字

违反迪米特原则代码:

代码图(1.1):


为什么违反迪米特原则:

迪米特原则又叫做最少知道原则,首先要理解:

  • 何为最少知道原则,意思就是:两个类之间耦合性特别低,耦合性特别低就代表他们之间交互特别少,即一个类对自己依赖的类知道的越少越好,在代码图(1.1)这个例子中可以看出,StudentManager()类对Studnet()类创建了10个学生名字.知道的太多了

  • 不对外泄露信息:代码图(1.1)红框的代码,应该是在Student()内部完成,然后StudentManager()直接调用的

大白话解释:StudentManager()需要所有学生,正确的应该是Student()吧所有学生直接给StudentManager(),而不是给一个Student()对象,让StudentManager()自己去计算所有学生,在大白话一点就是:我问你要什么你就给我什么,不要让我来计算(一个类对自己依赖的类知道的越少越好),你的东西也别让我知道(不对外泄露信息)

还是比较绕口,来看看遵守迪米特原则的代码就直接恍然大悟了~

遵守迪米特原则:

public class Student{
    
    
    String name = "";///学生名字
    
     ///用来存储所有学生名字
    ArrayList<String> mList = new ArrayList<>();

    public Student(String name) {
    
    
        this.name = name;
    }

     /// 遵守迪米特原则 创建10个学生
    public List<String> newStudentName(){
    
    
        for (int i = 0; i < 10; i++) {
    
    
            mList.add(name+i);
            Log.i("dimiter:","现在是第 "+i+"个学生,名字为: "+mList.get(i));
        }
        return mList;
    }
}

public class StudentManager {
    
    
    public void getStudentNumber(Student student) {
    
    
        /// 遵守迪米特原则
        List<String> list = student.newStudentName();
        Log.i("dimiter:", "总共有 " + list.size() + "个学生 ");
    }
}

//使用代码:
//迪米特原则
StudentManager studentManager = new StudentManager();
studentManager.getStudentNumber(new Student("张三"));

Student()创建10个学生,然后给到StudentManager()遵守了:

最少知道(迪米特)原则一个类对自己依赖的类知道的越少越好并且不对外泄露信息,

一个对象应该对其他对象保持最少的了解

这里的最少了解就是指10个Student()学生

我只知道你有10个学生,不管你这10个学生是怎么来的

效果图(2.1):

开闭原则

开闭原则定义:

  • 开闭原则是编程中最基础,最重要的设计原则
  • 一个软件实体如类,模块和方法应该对拓展开放(对提供方),对修改关闭(对使用方),用抽象构建框架,用实现拓展细节(细节指实现代码)
  • 当软件需求要变化时,尽量通过拓展软件的实体的行为来实现变化,而不是通过修改已有的代码来实现变化
  • 遵守其他原则,以及使用设计模式的目的就是遵守开闭原则

未遵守开闭原则代码:

//形状类型
public abstract class Shape {
    
    
    /**
     * 用来判断类型
     * 1:Circular 圆形
     * 2:Rectangle 矩形
     */
    int type;
}

//圆形
public class Circular extends Shape {
    
    
    public Circular() {
    
    
        type = 1;
    }
}

//矩形
public class Rectangle extends Shape {
    
    
    public Rectangle() {
    
    
        type = 2;
    }
}
//开闭原则Manager类 
public class OpenManager {
    
    
    public void showShape(Shape shape){
    
    
        if (shape .type == 1) {
    
    
            drawCircular(shape);
        }else if (shape.type == 2){
    
    
            drawRectangle();
        }
    }

    private void drawRectangle() {
    
    
        Log.i("Open","创建矩形 ");
    }
    private void drawCircular(Shape shape) {
    
    
        Log.i("Open","创建圆形 ");
    }
}

//使用代码:
 //开闭原则
OpenManager openManager = new OpenManager();
openManager.showShape(new Circular());//创建圆
openManager.showShape(new Rectangle());//创建矩形 

效果图(2.2):

为什么没有遵守开闭原则:

开闭原则的最关键的定义是:

拓展开放(对提供方),对修改关闭(对使用方),用抽象构建框架,用实现拓展细节(细节指实现代码)

如果说我现在要新加一个三角形我该怎么做呢?

是这样写?

public class Triangle  extends Shape{
    
    
    public Triangle() {
    
    
        type = 3;
    }
}

public class OpenManager {
    
    
    public void showShape(Shape shape){
    
    
        if (shape .type == 1) {
    
    
            drawCircular();//创建圆
        }else if (shape.type == 2){
    
    
            drawRectangle();//创建矩形
        }else if(shape.type == 3){
    
    
            drawTriangle();//创建三角形
        }
    }
    private void drawTriangle() {
    
    
        Log.i("Open","创建三角形 ");
    }
}
//使用代码
//开闭原则
OpenManager openManager = new OpenManager();
openManager.showShape(new Circular());
openManager.showShape(new Rectangle());
openManager.showShape(new Triangle());

效果图(2.3):


这样写不仅在改的过程中容易导致代码的冲突,而且通过if else判断

如果我有100个图形呢?判断100次吗?

if lese if lese if lese if lese if lese if lese if lese if lese if lese if lese…?

这样写出错率太高了,而且没有遵守到拓展开放,修改关闭

遵守开闭原则代码:

public abstract class Shape {
    
    
    public abstract void showShape();
}

public class Circular extends Shape {
    
    
    @Override
    public void showShape() {
    
    
        Log.i("Open","创建圆形 ");
    }
}

public class Triangle  extends Shape{
    
    
    @Override
    public void showShape() {
    
    
        Log.i("Open","创建三角形 ");
    }
}

public class Rectangle extends Shape {
    
    
    @Override
    public void showShape() {
    
    
        Log.i("Open","创建矩形 ");
    }
}

public class OpenManager {
    
    
    public void showShape(Shape shape){
    
    
        //遵守开闭原则
        shape.showShape();
    }
}

//使用代码:
//开闭原则
OpenManager openManager = new OpenManager();
openManager.showShape(new Circular());
openManager.showShape(new Rectangle());
openManager.showShape(new Triangle());

分析:

  • 可以看出,即使现在新增加了一个三角形类(Triangle),只要继承自Shape就可以画出来,而且不用if else来判断,代码逻辑非常清晰
  • 这才是真正的对扩展开发,对修改关闭,即使我现在在增加一个椭圆形,我自需要继承自Shape()然后输出一下即可
public class Ellipse  extends Shape{
    
    
    @Override
    public void showShape() {
    
    
        Log.i("Open","我是新创建的椭圆形哦");
    }
}
 //开闭原则
OpenManager openManager = new OpenManager();
openManager.showShape(new Circular());
openManager.showShape(new Rectangle());
openManager.showShape(new Triangle());
openManager.showShape(new Ellipse());//创建椭圆形

依赖倒置原则有点类似,只不过依赖倒置原则是通过接口来实现,开闭原则是通过抽象来实现.

合成复用原则

合成复用原则定义:

软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现


通常类的复用分为继承复用和合成复用两种,继承复用虽然有简单和易实现的优点,但它也存在以下缺点

  • 继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
  • 子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
  • 它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化

大白话翻译:
尽量不要继承,如果继承的话子类与父类耦合度高,父类对于子类是透明的.不利于维护,如果非要复用的话可以使用组合/聚合的方式.

不了解组合/聚合没关系,下一章我会详细介绍类与类之间的关系!

设计原则的核心思想

  • 找出应用中可能需要的变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起。
  • 面向接口编程,而不是针对实现编程。
  • 为了交互对象之间的松耦合设计而努力。
  • 拓展开放(对提供方),对修改关闭(对使用方),用抽象构建框架,用实现拓展细节(细节指实现代码)

迪米特(最少知道)原则代码

开闭原则

设计模式总结:

  • 开闭(OCP)原则: 拓展开放,修改关闭
  • 接口隔离原则:类之间的依赖关系应该建立在最小的接口上
  • 单一职责原则:一个类负责一项职责,而不是一个类负责一个职责
  • 依赖倒置原则:面向接口编程
  • 里氏替换原则:在继承时,在子类中尽量不要去重写父类的方法,如果非要使用,可以使用聚合,组合,依赖来解决问题,不要修改父类的方法!
  • 迪米特(最少知道)原则:只与直接朋友通信,一个类对自己依赖的类知道的越少越好,不对外泄露信息
  • 合成复用原则:要尽量使用组合或聚合的关系来实现,其次在考虑继承

猜你喜欢:

去设计模式/设计原则目录页

原创不易,记得点个赞哦~

猜你喜欢

转载自blog.csdn.net/weixin_44819566/article/details/112257643