SOLID 原则

▪ (SRP) The Single Responsibility Principle 单一责任原则

▪ (OCP) The Open-Closed Principle 开放-封闭原则

▪ (LSP) The Liskov Substitution Principle Liskov替换原则

▪ (DIP) The Dependency Inversion Principle 依赖转置原则

▪ (ISP) The Interface Segregation Principle 接口聚合原则

1. 单一责任原则

不应该有多于1个原因让你的ADT发生变化,否则就拆分开。

当粗粒度的类方法和属性太多,可以对这个类进行重构,拆分成粒度更细的类。

// 把用户类的注册登录,和发送邮件拆开。

// UserService类负责用户相关的操作,如用户注册、登录等
class UserService {
    public void registerUser(String username, String password) {
        // 实现用户注册逻辑
    }

    public boolean loginUser(String username, String password) {
        // 实现用户登录逻辑
        return false;
    }

    public void resetPassword(String username, String newPassword) {
        // 实现重置用户密码逻辑
    }
}

// EmailService类负责发送邮件
class EmailService {
    public void sendEmail(String to, String subject, String body) {
        // 实现发送邮件逻辑
    }
}

// 用户管理类,负责用户的管理操作,如注册、登录等,并在需要时发送邮件通知用户
class UserManager {
    private UserService userService;
    private EmailService emailService;

    public UserManager(UserService userService, EmailService emailService) {
        this.userService = userService;
        this.emailService = emailService;
    }

    public void registerUser(String username, String password) {
        userService.registerUser(username, password);
        emailService.sendEmail(username, "Welcome", "Welcome to our platform!");
    }

    public boolean loginUser(String username, String password) {
        return userService.loginUser(username, password);
    }

    public void resetPassword(String username, String newPassword) {
        userService.resetPassword(username, newPassword);
        emailService.sendEmail(username, "Password Reset", "Your password has been reset successfully.");
    }
}

2. 开放-封闭原则

对扩展性的开放:模块的行为应是可扩展的,从而该模块可表现出新的行为以满足需求的变化

对修改的封闭:但模块自身的代码是不应被修改的。扩展模块行为的一般途径是修改模块的内部实现;如果一个模块不能被修改,那么它通常被认为是具有固定的行为。

当修改软件功能的时候,不能修改原有代码,只能新增代码。

考虑使用接口或抽象类,去代替掉一堆if-else

// 当需要新增一个新的图表类型时,
// 只需要创建新的图表类并实现Chart接口,而不需要修改Display类的代码

// 定义图表接口
interface Chart {
    void display();
}

// 饼状图类
class PieChart implements Chart {
    @Override
    public void display() {
        // 实现饼状图的绘制逻辑
    }
}

// 柱状图类
class BarChart implements Chart {
    @Override
    public void display() {
        // 实现柱状图的绘制逻辑
    }
}

// 折线图类
class LineChart implements Chart {
    @Override
    public void display() {
        // 实现折线图的绘制逻辑
    }
}

// Display 类用于绘制各种类型的图表
class Display {
    private Chart chart;

    public void setChart(Chart chart) {
        this.chart = chart;
    }

    public void display() {
        if (chart != null) {
            chart.display();
        }
    }
}

3. Liskov替换原则

子类型必须能够替换其基类型;派生类必须能够通过其基类的接口使用,客户端无需了解二者之间的差异。

Liskov替换原则也是对开闭原则的补充,不仅适用于继承关系,还适用于实现关系的设计,常提到的 is a 关系是针对行为方式来说的,如果两个类的行为方式是不相容,那么就不应该使用继承,更好的方式是提取公共部分的方法来代替继承。

如:正方形/长方形问题。

如果 

class Square extends Rectangle

Square类继承自Rectangle类,看起来似乎是符合“is-a”关系,即正方形是长方形的一种特殊情况。但问题在于,Square类中重写了设置长度和宽度的方法,使得在设置正方形的边长时,也会同时修改另一个边,这违反了长方形的定义,因为长方形的长度和宽度可以是不同的。  

Rectangle r = ...; // 返回具体类型对象
r.setWidth(5);
r.setLength(2);
assert(r.area() == 10);

当返回具体类型对象为 Suqare 类型,面积为 10 的断言就是失败。 

改进:

interface Shape {
    double calculateArea();
}

class Rectangle implements Shape {
    protected double length;
    protected double width;

    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }

    // get,set 略   

    @Override
    public double calculateArea() {
        return length * width;
    }
}

class Square implements Shape {
    private double sideLength;

    public Square(double sideLength) {
        this.sideLength = sideLength;
    }

    // get,set 略 

    @Override
    public double calculateArea() {
        return sideLength * sideLength;
    }
}

4. 依赖转置原则

抽象的模块不应依赖于具体的模块。具体应依赖于抽象。

高层模块不应该依赖低层模块,应该共同依赖抽象。

delegation的时候, 要通过加装一层interface建立联系,而非具体子类

// 定义一个接口来抽象发送消息的行为
interface MessageSender {
    void sendMessage(String message);
}

// 具体的消息发送类,实现了MessageSender接口
class EmailSender implements MessageSender {
    @Override
    public void sendMessage(String message) {
        // 实现发送邮件的逻辑
        System.out.println("Sending email: " + message);
    }
}

// 具体的消息发送类,实现了MessageSender接口
class SMSSender implements MessageSender {
    @Override
    public void sendMessage(String message) {
        // 实现发送短信的逻辑
        System.out.println("Sending SMS: " + message);
    }
}

// 高层模块,依赖于抽象MessageSender接口
class NotificationService {
    private MessageSender messageSender;

    // 通过构造函数注入依赖
    public NotificationService(MessageSender messageSender) {
        this.messageSender = messageSender;
    }

    // 业务逻辑方法,发送通知
    public void sendNotification(String message) {
        messageSender.sendMessage(message);
    }
}

5. 接口聚合原则

客户端不应该依赖那些它不需要的接口。客户端应该只依赖它实际使用的方法。

减少定义大而全的接口,类所要实现的接口应该分解成多个接口,然后根据所需要的功能去实现,并且在使用到接口方法的地方,用对应的接口类型去声明,这样可以解除调用方与对象非相关方法的依赖关系。以防止暴露给客户端无相关的代码和方法,避免出现无关、不需要的部分。

// 将动物接口拆分成多个小的接口
// 避免interface Animal 下面同时包括 fly() 和 swim()
// 否则class Bird implements Animal 还要 @Override swim()

interface Flyable {
    void fly();
}

interface Swimmable {
    void swim();
}

// 实现了飞行接口的鸟类
class Bird implements Flyable {
    @Override
    public void fly() {
        // 实现飞行的逻辑
    }
}

// 客户端代码只需要使用飞行的动物
class Client {
    public void process(Flyable flyingAnimal) {
        flyingAnimal.fly();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值