Java基础知识整理——软件设计六大原则(单一职责原则与开闭原则)

六大设计原则是面向对象设计的基石,掌握好它,会让我们在后期的软件开发旅程中事半功倍。

 

一、六大设计原则概念:

1、单一职责原则(Single Responsibility Principle):一个模块、类、方法只做和它相关一系列或者一件事。

2、开闭原则(Open-Closed Principle):对扩展开放,对修改关闭。

3、里氏替换原则(Liskov Substitution Principle):继承方面,子类必须能够替换父类,凡是使用父类能完成的事,使用子类也可以同样完成,子类不能修改父类的语义。

4、接口隔离原则(Interface Segregation Principle):接口要小而专,通过组合实现更复杂的接口。

5、依赖倒置原则(Dependency Inversion Principle):高层模块不应该依赖底层模块的具体实现,而是都应依赖于抽象(接口或抽象类)。抽象不应依赖细节,而细节应依赖抽象。

6、迪米特法则(Law of Demeter):最少知识原则,将多余的操作封装起来,每次调用只涉及一个方法。

 

二、如果违反六大设计原则将引入哪些问题:

1、违反单一职责原则:

比如说我们有一个电商系统,有支付模块、订单模块、库存模块等等,如果我们把所有的功能放在一个类中,那么这个类就会非常臃肿而且难以维护,修改其中任何一个地方都可能影响到别的功能。我们应该按照模块先做一级分类,再根据具体业务功能做二级分类,具体到类中的方法,一个方法只完成一件事,做到三级分类,这样模块、类、方法。保持逻辑、有序的三级序列,无论是扩展还是修改,都容易清晰的定位问题。

联系到实际,我们阅读技术书籍时,比如说《Java核心技术卷Ⅰ》,如果没有目录,所有的内容都放到一章里面,那么我们学起来就很费力,这本书有654页,如果不分章节,不分小节的话,阅读起来实在太难了。而现实是,首先有目录,让我们知道有多少章,其次有小节,让我们知道每章大概有多少内容,这种结构就很清晰。我想软件开发也是这样,尽量用逻辑清晰的结构,每个模块、类、方法只负责一个职责。

(1)错误代码示例:

public class OrderService {

    public void createOrder(Order order) {
        // 创建订单
        System.out.println("订单已创建,订单ID:" + order.getOrderId());

        // 发送短信
        System.out.println("发送短信给 " + order.getUserPhone() + ":您的订单已生成");

        // 发送邮件
        System.out.println("发送邮件给 " + order.getUserEmail() + ":您的订单已生成,请注意查收");
       
    }
}

(2)正确代码示例:

// 负责发送短信
public class SmsService {
    public void sendSms(String phoneNumber, String message) {
        // 发送短信逻辑
        System.out.println("发送短信给 " + phoneNumber + ":" + message);
    }
}

// 负责发送邮件
public class EmailService {
    public void sendEmail(String email, String subject, String content) {
        // 发送邮件逻辑
        System.out.println("发送邮件给 " + email + ":" + subject + " - " + content);
    }
}

// 负责订单创建
public class OrderService {
    private SmsService smsService = new SmsService();
    private EmailService emailService = new EmailService();

    public void createOrder(Order order) {
        // 创建订单的核心逻辑
        System.out.println("订单已创建,订单ID:" + order.getOrderId());

        // 通知用户
        smsService.sendSms(order.getUserPhone(), "您的订单已生成");
        emailService.sendEmail(order.getUserEmail(), "订单确认", "您的订单已生成,请注意查收");
    }
}

 

对比错误示例以及正确示例,我们发现,违反单一职责的代码只有一个类,但是却在一个方法中做了3件事,如果将来业务变化,比如短信业务调整那么就需要修改代码,由于所有业务逻辑都在一个类的方法里面,有较大可能引入风险和BUG。

 

而正确的示例有三个类,每个类只做一件事,程序运行时,通过组合的方式,完成业务功能。将来业务变化时,无论是新增还是已有的服务变化,都不会影响orderService的逻辑。

 

2、违反开闭原则:

就用电商场景举例,比如说我们下单后,会受到短信和邮件提醒,将来还会收到app提醒以及微信公众号提醒。

这次我们先看代码,在说理解。

(1)错误代码示例:

public class OrderService {

    public void createOrder(Order order, String notifyType) {
        // 创建订单
        System.out.println("订单已创建,订单ID:" + order.getOrderId());

        // 根据类型发送通知
        if ("sms".equals(notifyType)) {
            sendSms(order.getUserPhone());
        } else if ("email".equals(notifyType)) {
            sendEmail(order.getUserEmail());
        } else if ("app".equals(notifyType)) {
            sendAppMessage(order.getUserId());
        }
    }

    private void sendSms(String phone) {
        System.out.println("发送短信给:" + phone);
    }

    private void sendEmail(String email) {
        System.out.println("发送邮件给:" + email);
    }

    private void sendAppMessage(Long userId) {
        System.out.println("发送 App 消息给用户ID:" + userId);
    }
}

假如现在要新增微信公众号推送,那么我们就需要修改代码,增加if逻辑,同时添加一个新方法。在修改代码逻辑的时候,就容易犯错,并且单元测试要重跑。

(2)正确代码示例:

①实体类:

public class Order {
    private Long orderId;
    private String userPhone;
    private String userEmail;
    private Long userId;

    // 构造方法、getter/setter 省略
    public Order(Long orderId, String userPhone, String userEmail, Long userId) {
        this.orderId = orderId;
        this.userPhone = userPhone;
        this.userEmail = userEmail;
        this.userId = userId;
    }

    public Long getOrderId() {
        return orderId;
    }

    public String getUserPhone() {
        return userPhone;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public Long getUserId() {
        return userId;
    }
}

②抽象接口:

public interface NotificationService {
    void notifyUser(Order order);
}

③通知实现类:

public class SmsNotification implements NotificationService {
    @Override
    public void notifyUser(Order order) {
        System.out.println("发送短信给 " + order.getUserPhone() + ":您的订单已生成");
    }
}
public class EmailNotification implements NotificationService {
    @Override
    public void notifyUser(Order order) {
        System.out.println("发送邮件给 " + order.getUserEmail() + ":您的订单已生成");
    }
}
public class AppNotification implements NotificationService {
    @Override
    public void notifyUser(Order order) {
        System.out.println("发送 App 消息给用户ID:" + order.getUserId() + ":您的订单已生成");
    }
}

④订单服务类:

import java.util.ArrayList;
import java.util.List;

public class OrderService {

    private List<NotificationService> notifications = new ArrayList<>();

    // 添加通知方式
    public void addNotification(NotificationService service) {
        notifications.add(service);
    }

    public void createOrder(Order order) {
        // 创建订单逻辑
        System.out.println("订单已创建,订单ID:" + order.getOrderId());

        // 调用所有通知服务
        for (NotificationService notification : notifications) {
            notification.notifyUser(order);
        }
    }
}

⑤测试类:

public class TestMain {
    public static void main(String[] args) {
        // 创建订单对象
        Order order = new Order(1001L, "13800138000", "user@example.com", 9527L);

        // 创建订单服务
        OrderService orderService = new OrderService();

        // 添加多种通知方式
        orderService.addNotification(new SmsNotification());
        orderService.addNotification(new EmailNotification());
        orderService.addNotification(new AppNotification());

        // 创建订单并通知
        orderService.createOrder(order);
    }
}

当需求变化时,比如说不需要邮件提醒了,那么我们不添加邮件服务就行,比如说短信运营商修改,那么只需要改短信业务的配置,或者新增一个实现类即可。业务逻辑是不用修改的。

给自己一个正确的学习方向,以前写代码,大部分考虑的是实现,但是无形中已经违反这些原则了,后续的开发要给自己提个醒。

 

未完待续。。。6月19日继续补充。

 

posted @ 2025-06-18 17:14  hebtu小白  阅读(12)  评论(0)    收藏  举报