首页 > 其他分享 >面向对象设计的6大原则

面向对象设计的6大原则

时间:2024-07-04 22:44:11浏览次数:20  
标签:原则 Notification void class 面向对象 EmailService 设计 message public

一.软件设计的六大原则,通常被称为SOLID原则,
是面向对象设计(OOD)中最重要的指导方针之一。这些原则旨在提高软件的可维护性、可扩展性和可读性。以下是SOLID原则的详细解释:

1. 单一职责原则 (Single Responsibility Principle, SRP)

单一职责原则指出,一个类应该只有一个引起它变化的原因,即一个类应该只有一个职责。这样可以减少类的复杂性,增加代码的可维护性。

示例:

class User {
    private String name;
    private String email;
    
    // getters and setters
}

class UserService {
    public void createUser(User user) {
        // 业务逻辑
    }
}

class UserRepository {
    public void saveUser(User user) {
        // 数据库操作
    }
}

2. 开放/封闭原则 (Open/Closed Principle, OCP)

开放/封闭原则指出,软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。这意味着应通过扩展类的行为来实现功能的变化,而不是修改现有的代码。

示例:

abstract class Shape {
    abstract void draw();
}

class Circle extends Shape {
    void draw() {
        // 画圆
    }
}

class Rectangle extends Shape {
    void draw() {
        // 画矩形
    }
}

3. 里氏替换原则 (Liskov Substitution Principle, LSP)

里氏替换原则指出,子类必须能够替换掉它们的父类。这意味着子类应该在任何父类能够出现的地方都能使用,并且行为不会改变。

示例:

class Rectangle {
    private int width;
    private int height;

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }
}

class Square extends Rectangle {
    // 重写方法确保正方形的特性
    @Override
    public void setWidth(int width) {
        super.setWidth(width);
        super.setHeight(width);
    }

    @Override
    public void setHeight(int height) {
        super.setWidth(height);
        super.setHeight(height);
    }
}

4. 接口隔离原则 (Interface Segregation Principle, ISP)

接口隔离原则指出,客户端不应该被迫依赖它们不需要的接口。应将接口划分为多个小接口,使每个接口只包含客户端感兴趣的方法。

示例:

interface Worker {
    void work();
}

interface Eater {
    void eat();
}

class Robot implements Worker {
    public void work() {
        // 机器人工作
    }
}

class Human implements Worker, Eater {
    public void work() {
        // 人类工作
    }

    public void eat() {
        // 人类吃饭
    }
}

5. 依赖倒置原则 (Dependency Inversion Principle, DIP)

依赖倒置原则指出,高层模块不应该依赖低层模块,二者都应该依赖其抽象。具体实现应该依赖抽象,而不是抽象依赖具体实现。

示例:

interface MessageService {
    void sendMessage(String message);
}

class EmailService implements MessageService {
    public void sendMessage(String message) {
        // 发送电子邮件
    }
}

class SMSService implements MessageService {
    public void sendMessage(String message) {
        // 发送短信
    }
}

class Notification {
    private MessageService messageService;

    public Notification(MessageService messageService) {
        this.messageService = messageService;
    }

    public void notify(String message) {
        messageService.sendMessage(message);
    }
}

6. 迪米特法则 (Law of Demeter, LoD)

迪米特法则,也称为最少知识原则,指出一个对象应该对其他对象有尽可能少的了解。每个单元只应与它的直接朋友通信,而不是与陌生人通信。

示例:

class Engine {
    public void start() {
        // 启动引擎
    }
}

class Car {
    private Engine engine;

    public Car() {
        this.engine = new Engine();
    }

    public void startCar() {
        engine.start();
    }
}

总结

  • 单一职责原则(SRP):每个类只有一个职责。
  • 开放/封闭原则(OCP):对扩展开放,对修改封闭。
  • 里氏替换原则(LSP):子类必须能够替换掉它们的父类。
  • 接口隔离原则(ISP):使用多个专门的接口,而不是一个总接口。
  • 依赖倒置原则(DIP):依赖于抽象,而不是具体实现。
  • 迪米特法则(LoD):一个对象应对其他对象有尽可能少的了解。

这些原则共同帮助软件设计者创建灵活、可维护、可扩展的系统。


二. 那么还是以5.依赖倒置原则这个例子为基础,违反依赖倒置的例子是什么样子?
违反依赖倒置原则(Dependency Inversion Principle, DIP)的例子通常是高层模块直接依赖于低层模块的实现细节,而不是依赖于抽象。这会导致代码的耦合度增加,难以维护和扩展。

违反依赖倒置原则的例子

问题描述

假设我们有一个通知系统(Notification System),它发送消息(Message)给用户。我们有一个具体的邮件服务(EmailService)来发送电子邮件。高层模块(Notification类)直接依赖于具体的邮件服务(EmailService)。

代码示例

// 具体的邮件服务类
class EmailService {
    public void sendEmail(String message) {
        // 发送电子邮件的具体实现
        System.out.println("Sending email: " + message);
    }
}

// 高层模块,通知类
class Notification {
    private EmailService emailService;

    public Notification() {
        this.emailService = new EmailService();
    }

    public void notify(String message) {
        emailService.sendEmail(message);
    }
}

public class Main {
    public static void main(String[] args) {
        Notification notification = new Notification();
        notification.notify("Hello, this is a notification!");
    }
}

问题分析

  1. 高耦合Notification类直接依赖于具体的EmailService类。这使得Notification类与EmailService类紧密耦合。
  2. 难以扩展:如果我们想要增加一个新的消息服务(如SMS服务),我们需要修改Notification类的代码。这违反了开放/封闭原则(OCP),使得系统难以扩展。
  3. 难以测试:在单元测试中,我们无法轻易替换EmailService,因为Notification类直接创建了EmailService的实例。

解决方案:依赖倒置原则

通过依赖倒置原则,我们可以重构代码,使高层模块依赖于抽象,而不是具体实现。

重构后的代码示例

// 抽象的消息服务接口
interface MessageService {
    void sendMessage(String message);
}

// 具体的邮件服务类实现接口
class EmailService implements MessageService {
    public void sendMessage(String message) {
        // 发送电子邮件的具体实现
        System.out.println("Sending email: " + message);
    }
}

// 高层模块,通知类依赖于抽象接口
class Notification {
    private MessageService messageService;

    public Notification(MessageService messageService) {
        this.messageService = messageService;
    }

    public void notify(String message) {
        messageService.sendMessage(message);
    }
}

public class Main {
    public static void main(String[] args) {
        // 依赖注入具体实现
        MessageService emailService = new EmailService();
        Notification notification = new Notification(emailService);
        notification.notify("Hello, this is a notification!");
    }
}

重构后的优点

  1. 低耦合Notification类不再直接依赖于具体的EmailService类,而是依赖于MessageService接口。这降低了类之间的耦合度。
  2. 易于扩展:要增加新的消息服务(如SMS服务),只需实现MessageService接口,并在创建Notification实例时传递新的实现即可,无需修改现有的Notification类代码。
  3. 易于测试:在单元测试中,可以轻松地替换MessageService接口的实现,使用模拟(mock)对象来测试Notification类。

这里,违反依赖倒置原则的代码示例展示了高层模块直接依赖低层模块的实现细节,从而导致高耦合和低扩展性。通过引入抽象接口并依赖于这些接口,可以遵循依赖倒置原则,提高代码的灵活性、可维护性和可测试性。


三.那么还是以6. 迪米特法则中这个例子为基础,违反迪米特法则的例子是什么样子?
违反依赖倒置原则(Dependency Inversion Principle, DIP)的例子通常是高层模块直接依赖于低层模块的实现细节,而不是依赖于抽象。这会导致代码的耦合度增加,难以维护和扩展。

违反依赖倒置原则的例子

问题描述

假设我们有一个通知系统(Notification System),它发送消息(Message)给用户。我们有一个具体的邮件服务(EmailService)来发送电子邮件。高层模块(Notification类)直接依赖于具体的邮件服务(EmailService)。

代码示例

// 具体的邮件服务类
class EmailService {
    public void sendEmail(String message) {
        // 发送电子邮件的具体实现
        System.out.println("Sending email: " + message);
    }
}

// 高层模块,通知类
class Notification {
    private EmailService emailService;

    public Notification() {
        this.emailService = new EmailService();
    }

    public void notify(String message) {
        emailService.sendEmail(message);
    }
}

public class Main {
    public static void main(String[] args) {
        Notification notification = new Notification();
        notification.notify("Hello, this is a notification!");
    }
}

问题分析

  1. 高耦合Notification类直接依赖于具体的EmailService类。这使得Notification类与EmailService类紧密耦合。
  2. 难以扩展:如果我们想要增加一个新的消息服务(如SMS服务),我们需要修改Notification类的代码。这违反了开放/封闭原则(OCP),使得系统难以扩展。
  3. 难以测试:在单元测试中,我们无法轻易替换EmailService,因为Notification类直接创建了EmailService的实例。

解决方案:依赖倒置原则

通过依赖倒置原则,我们可以重构代码,使高层模块依赖于抽象,而不是具体实现。

重构后的代码示例

// 抽象的消息服务接口
interface MessageService {
    void sendMessage(String message);
}

// 具体的邮件服务类实现接口
class EmailService implements MessageService {
    public void sendMessage(String message) {
        // 发送电子邮件的具体实现
        System.out.println("Sending email: " + message);
    }
}

// 高层模块,通知类依赖于抽象接口
class Notification {
    private MessageService messageService;

    public Notification(MessageService messageService) {
        this.messageService = messageService;
    }

    public void notify(String message) {
        messageService.sendMessage(message);
    }
}

public class Main {
    public static void main(String[] args) {
        // 依赖注入具体实现
        MessageService emailService = new EmailService();
        Notification notification = new Notification(emailService);
        notification.notify("Hello, this is a notification!");
    }
}

重构后的优点

  1. 低耦合Notification类不再直接依赖于具体的EmailService类,而是依赖于MessageService接口。这降低了类之间的耦合度。
  2. 易于扩展:要增加新的消息服务(如SMS服务),只需实现MessageService接口,并在创建Notification实例时传递新的实现即可,无需修改现有的Notification类代码。
  3. 易于测试:在单元测试中,可以轻松地替换MessageService接口的实现,使用模拟(mock)对象来测试Notification类。

违反依赖倒置原则的代码示例展示了高层模块直接依赖低层模块的实现细节,从而导致高耦合和低扩展性。通过引入抽象接口并依赖于这些接口,可以遵循依赖倒置原则,提高代码的灵活性、可维护性和可测试性。

标签:原则,Notification,void,class,面向对象,EmailService,设计,message,public
From: https://www.cnblogs.com/gongchengship/p/18284823

相关文章

  • 23种设计模式
    23种设计模式通常分为三大类:创建型模式(CreationalPatterns)、结构型模式(StructuralPatterns、行为型模式(BehavioralPatterns)。每一类设计模式都有其独特的用途和特点,以下是详细的分类和解释:创建型模式(CreationalPatterns)创建型模式主要用于对象的创建,这些模式通过将对......
  • 信息安全体系架构设计
        对信息系统的安全需求是任何单一安全技术都无法解决的,要设计一个信息安全体系架构,应当选择合适的安全体系结构模型。信息系统安全设计重点考虑两个方面;其一是系统安全保障体系;其二是信息安全体系架构。1.系统安全保障体系     安全保障体系是由安全服务......
  • 课程设计——基于FPGA的双向移位寄存器
    基于FPGA的双向移位寄存器摘 要本文使用verilogHDL语言设计双向移位寄存器,使电路受外部信号控制,实现数字信号的双向移位等功能,其电路设计模块主要分为三个部分,分别为接受判断控制信号的组合逻辑电路部分、实现存储、运算和输出数据的时序逻辑电路部分以及时钟信号输入部分......
  • 精品在线试题库系统设计与实现
    摘 要使用旧方法对作业管理信息进行系统化管理已经不再让人们信赖了,把现在的网络信息技术运用在作业管理信息的管理上面可以解决许多信息管理上面的难题,比如处理数据时间很长,数据存在错误不能及时纠正等问题。这次开发的精品在线试题库系统有管理员,教师,学生三个角色。管理员......
  • 模拟集成电路设计系列博客——9.2 电平转换器
    模拟集成电路设计9.2电平转换器电平转换器是集成电路设计中的一个重要部分,常用于芯片多电压域低功耗设计和I/O中。我们知道在集成电路中,I/O电压与Core电压常常处于两个不同的电压域,因此我们需要使用电平转换器(levelshifter)来将I/O电压降低到Core电压,或者将Core电压抬升到I/O电......
  • 想要流程化办公,不妨了解拖拽式报表设计器!
    当前,经济发展越来越快,经济水平提升的同时也给职场人提成了更高的要求。很多领域的客户都希望能实现降本、提质、增效,进入流程化办公新时代,可以先来了解低代码技术平台、拖拽式报表设计器的更多功能和优势特点。看看拖拽式报表设计器是如何为客户降低成本、提高效率,携手进入产业分......
  • 跟我一起学习和开发动态表单系统-数据库设计(1)
    在当今的企业信息系统中,动态表单是一种非常常见的功能,它能够根据业务需求灵活地调整表单结构,以满足不同的数据收集和展示需求。而动态表单的核心在于其背后的数据库设计。本文将探讨动态表单的数据库设计方法论,主要包括设计原则、方法以及具体实现方案。一、设计原则1.模块化设......
  • 《阻抗放大器设计参考》章节摘取
    原理图(SCH)设计中通常假定PCB(印制电路板)是理想的,因此PCB布局布线中就要关注非理想因素带来的影响。低电流检测的应用中,需要避免PCB上产生漏电流;高速高带宽应用中,需要减小PCB上的寄生电容。1.漏电流PCB一般基于FR-4玻璃纤维基材涂环氧树脂经半固化后制成,无法达到理想......
  • 关于领域驱动设计,大家都理解错了
    翻遍整个互联网,我发现,关于领域驱动设计,大家都**理解错了**。今天,我们尝试通过一篇文章的篇幅,给大家展示一个完全不同的视角,把“领域驱动设计”这六个字解释清楚。##领域驱动设计学习资料现状 领域驱动设计的概念提出已经有20年的时间了,整个互联网充斥着大量书籍、文章和视频......
  • 实用麦克风话筒音频放大器电路设计和电路图
    设计目标输入电压最大值输出电压最大值电源Vcc电源Vee频率响应偏差@20Hz频率响应偏差@20kHz100dBSPL(2Pa)1.228Vrms5V0V–0.5dB–0.1dB设计说明此电路使用跨阻抗放大器配置中的运算放大器将驻极体炭精盒麦克风的输出电流转换为输出电压。此电路的共模电压是固定的,设置为......