软件设计原则

单一职责

描述:一个类、方法或模块只负责一项功能。

场景举例:设计账户信息类时,会有账号、密码、电话、地址等基本信息。最简单的就是将所有属性放到同一个类中。在实际中,我们使用购物软件时可能会保存多个地址信息,那么原先的设计就不能满足需求了。这时需要单独一个类保存地址信息。这便体现了单一职责原则。

代码示例:

修改前:

package com.zf.design.principle;

import lombok.Data;

@Data
public class UserInfo {
    private String account;
    private String password;
    private String phone;
    private String address;
}

修改后:

package com.zf.design.principle;

import lombok.Data;

@Data
public class AddressInfo {
    private String phone;
    private String address;
}


package com.zf.design.principle;

import lombok.Data;

import java.util.List;

@Data
public class UserInfo {
    private String account;
    private String password;
    private List<AddressInfo> address;
}

开闭原则

对扩展开放,对修改关闭。通过扩展代码来实现新功能,而不是修改代码。

场景举例:画不同的图形,画圆形、三角形。

代码示例:

修改前:定义绘画类,添加画圆形方法,画三角形方法。如果要再画正方形怎么办呢,需要修改绘画类。如果该类是别人写的可能修改不了,而且修改可能会引入错误,这不是我们想要的。

package com.zf.design.principle;

public class Draw {

    public void drawCircle() {
        System.out.println("draw circle-------");
    }

    public void drawRectangle() {
        System.out.println("draw rectangle-------");
    }
}

修改后:使用抽象和接口定义可扩展的点。定义形状接口Shape及绘画方法,所有形状实现Shape接口。有新的形状则实现Shape接口即可

public interface Shape {
    void draw();
}



public class Circle implements Shape{
    @Override
    public void draw() {
        System.out.println("draw circle-------");
    }
}


public class Rectangle implements Shape{
    @Override
    public void draw() {
        System.out.println("draw rectangle-------");
    }
}

接口隔离原则

类继承最小接口集合,避免实现其他不需要的接口方法。即将接口拆分成最小单元提高灵活性及可复用性。

场景举例:动物有天上飞的,有地上跑的,会吃东西等,如果把这些行为放到同一个接口就会造成冗余。

修改前:对于Dog来说,fly()方法就是多余的

package com.zf.design.principle;

public interface Animal {
    
    void eat();
    
    void run();
    
    void fly();
}


package com.zf.design.principle;

public class Dog implements Animal{
    @Override
    public void eat() {

    }

    @Override
    public void run() {

    }

    @Override
    public void fly() {

    }
}

修改后:Dog只需要实现它需要的接口

public interface Eatable {
    void eat();
}

package com.zf.design.principle;

public interface Runnnable {
    void run();
}

package com.zf.design.principle;

public interface Flyable {
    void fly();
}


package com.zf.design.principle;

public class Dog implements Eatable, Runnnable {
    @Override
    public void eat() {

    }

    @Override
    public void run() {

    }
}

依赖倒置原则

高层模块依赖低层模块翻转过来,高层模块需要什么,低层模块给什么。高层模块依赖抽象而不依赖具体实现。

场景举例:造汽车,汽车依赖依赖底盘,底盘依赖轮子。如果汽车需要的轮子尺寸不同,则需要修改每个类传入轮子尺寸

修改前:

修改后:Car依赖类而不是具体的实现。修改Tire尺寸只需要修改Tire类。接口定义好后可以多人同时开发具体实现细节;单元测试只需要给Car传Framework而不用关心底层的Buttom等。

以上图片来源:https://www.zhihu.com/question/23277575/answer/169698662

迪米特原则

迪米特是个i人,与他人保持最少的联系。不同模块之间尽可能少了解彼此的细节,降低代码的复杂性和耦合度,提高代码的可读性和可维护性。

场景举例:学校由若干班级组成,班级有若干学生。在此场景下学校只与班级发生联系,而不需关心学生的实现细节

代码示例:学校打印所有班级,不需要关心学生信息

package com.zf.design.principle;

import lombok.Data;

@Data
public class Student {
    private String name;
    private int age;
    private String school;

    public Student(String name, int age, String school) {
        this.name = name;
        this.age = age;
        this.school = school;
    }

    public void printStudent(){
        System.out.println("我是" + name + ",今年" + age + "岁,就读于" + school);
    }
}


package com.zf.design.principle;

import lombok.Data;

import java.util.List;

@Data
public class Class {
    private String name;
    private List<Student> students;

    public Class(String name, List<Student> students) {
        this.name = name;
        this.students = students;
    }

    public void printStudents(){
        students.forEach((student)->System.out.println(student.getName()));
    }
}


package com.zf.design.principle;

import lombok.Data;

import java.util.List;

@Data
public class School {
    private String name;
    private List<Class> classes;

    public School(String name, List<Class> classes) {
        this.name = name;
        this.classes = classes;
    }

    public void printClasses(){
        classes.forEach(
                classes -> System.out.println(classes.getName())
        );
    }
}


package com.zf.design.principle;

import java.util.ArrayList;
import java.util.Arrays;

public class MainRunner {
    public static void main(String[] args) {
        // 不需要关心student细节
        Class mainClass1 = new Class("一年一班", new ArrayList<>());
        Class mainClass2 = new Class("一年二班",new ArrayList<>());
        School school = new School("清华中学",Arrays.asList(mainClass2,mainClass1));
        school.printClasses();
    }
}

里氏替换原则

子类替换父类,尽量避免重写父类方法,尽量遵循父类的约束和行为,不引入新的约束和行为

场景举例:类Ostrich重写了父类fly方法并抛出异常,与父类原有预期不一致。用户不知情的情况下使用了Ostrich的fly方法就会得到与预期不符的结果

// 基类  
class Bird {  
    public void fly() {  
        System.out.println("Flying high");  
    }  
}  
  
// 派生类,遵守LSP  
class Sparrow extends Bird {  
    @Override  
    public void fly() {  
        System.out.println("Sparrow is flying");  
    }  
}  
  
// 派生类,违反LSP(假设Ostrich不能飞)  
class Ostrich extends Bird {  
    @Override  
    public void fly() {  
        throw new UnsupportedOperationException("Ostrich cannot fly");  
    }  
}  
  
// 使用示例  
public class Main {  
    public static void letItFly(Bird bird) {  
        bird.fly();  
    }  
      
    public static void main(String[] args) {  
        letItFly(new Sparrow()); // 正常工作  
        // letItFly(new Ostrich()); // 抛出异常,违反LSP  
    }  
}

合成复用原则

能组合,不继承。尽量使用组合/聚合的方式达到复用目的,而不是通过继承。

// 通过组合/聚合来实现复用,而不是继承  
class Engine {  
    public void run() {  
        System.out.println("Engine is running");  
    }  
}  
  
class Car {  
    private Engine engine;  
  
    public Car(Engine engine) {  
        this.engine = engine;  
    }  
  
    public void start() {  
        engine.run();  
    }  
}  
  
// 使用示例  
public class Main {  
    public static void main(String[] args) {  
        Engine dieselEngine = new Engine() {  
            @Override  
            public void run() {  
                System.out.println("Diesel engine is running");  
            }  
        };  
          
        Car dieselCar = new Car(dieselEngine);  
        dieselCar.start(); // 输出: Diesel engine is running  
          
        // 可以很容易地替换成其他类型的引擎,而不需要修改Car类  
    }  
}

参考文章:

掌握这7种软件设计原则,让你的代码更优雅_常用的几种软件设计原则-CSDN博客

https://www.zhihu.com/question/23277575/answer/169698662

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值