六大设计原则

一、前言

在软件开发过程中,遵循良好的设计原则可以帮助我们构建出更加健壮、易于维护和扩展的系统,可能在此之前你也多少了了解过设计模式,但在实际的业务开发中使⽤用却不多,接下来我们将分别介绍这些原则及其重要性。

二、图示

三、内容

1. 单一职责原则

定义:单一职责原则指出每个类应该只有一个职责,即一个类只负责一项功能或一类功能的逻辑。

例子: 假设你有一个Order类,它负责处理订单信息同时也发送电子邮件通知,当需要修改电子邮件格式时,可能会影响到订单处理的逻辑,为了避免这种耦合,可以将发送邮件的功能提取到另一个类中,如EmailService

public class Order {
    private String orderId;
    private double amount;

    public Order(String orderId, double amount) {
        this.orderId = orderId;
        this.amount = amount;
    }

    // ... 其他订单相关方法 ...
}

public interface EmailService {
    void sendEmail(String message);
}

public class SimpleEmailService implements EmailService {
    @Override
    public void sendEmail(String message) {
        System.out.println("Sending email: " + message);
    }
}

好处:

  • 更容易测试和维护。
  • 降低模块间的耦合度。

2. 开放封闭原则

定义:开放封闭原则指的是软件实体(类、模块、函数等)应该是对扩展开放的,而对修改封闭
例子: 考虑一个支付系统,支持多种支付方式(信用卡PayPalApple Pay等)。可以通过继承和多态来实现新的支付方式,而不是修改现有代码。
应用:

  • 使用接口或抽象类:定义一个接口或抽象类,并通过不同的实现类来扩展功能。
  • 使用设计模式:策略模式、装饰器模式、工厂模式等设计模式都可以帮助实现开闭原则。
public interface PaymentMethod {
    void processPayment(double amount);
}

public class CreditCardPayment implements PaymentMethod {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing credit card payment of $" + amount);
    }
}

public class PayPalPayment implements PaymentMethod {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing PayPal payment of $" + amount);
    }
}

public class PaymentProcessor {
    private PaymentMethod method;

    public PaymentProcessor(PaymentMethod method) {
        this.method = method;
    }

    public void makePayment(double amount) {
        method.processPayment(amount);
    }
}

好处:

  • 减少修改现有代码的风险。
  • 提高系统的灵活性和可扩展性。

3. 里氏替换原则

定义:里氏替换原则指在一个程序中,如果基类可以被子类替换,而不影响程序的正确性,那么这个子类是正确的,即子类对象应该能够替换基类对象而不改变程序的行为。
例子: 假设有一个Shape类和它的子类SquareRectangle。如果Square重写了setWidth方法,那么用Square替换Rectangle时可能会导致意外的行为。
情况分类:

  • 如果AB的子类,则B的对象可以替换为A的对象,而不会破坏程序,这个是更为常见的。
  • 所有引用其父类对象方法的地方,都可以透明的替换为其子类对象——下列示例将展出。
public abstract class Shape {
    protected double width;
    protected double height;

    public Shape(double width, double height) {
        this.width = width;
        this.height = height;
    }

    public abstract double getArea();
}

public class Rectangle extends Shape {
    public Rectangle(double width, double height) {
        super(width, height);
    }

    @Override
    public double getArea() {
        return width * height;
    }
}

public class Square extends Shape {
    public Square(double side) {
        super(side, side);
    }

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

好处:

  • 保证继承关系的正确性。
  • 避免运行时错误。

4. 依赖倒置原则

定义:依赖倒置原则强调高层模块不应该依赖于低层模块,二者都应该依赖于抽象;且抽象不应该依赖于具体实现,具体实现应该依赖于抽象。
例子: 通过接口或抽象类来定义服务接口,具体的实现类依赖于这些接口或抽象类。
应用:

  • 依赖于抽象(接口或抽象类),而不是具体类:通过依赖于抽象,可以在不修改高层模块的情况下更换低层模块的实现。
  • 通过依赖注入来实现依赖倒置:使用构造器注入、方法注入或属性注入的方式,将具体实现传递给高层模块。
public interface Logger {
    void log(String message);
}

public class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("Console log: " + message);
    }
}

public class FileLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("File log: " + message);
    }
}

public class Service {
    private final Logger logger;

    public Service(Logger logger) {
        this.logger = logger;
    }

    public void doSomething() {
        logger.log("Doing something...");
    }
}

好处:

  • 提高系统的松耦合性。
  • 支持依赖注入等设计模式。

5. 接口隔离原则

定义:接口隔离原则强调客户不应该被迫依赖他们不使用的方法,且多个特定客户端接口要好于一个宽泛用途的接口,即其提倡将大接口拆分为多个小接口,使得接口更具针对性和灵活性——接口尽量细化,接口中的方法尽量少
例子: 如果你有一个Printer接口,其中包含打印和扫描功能,但有些打印机只支持打印,此时,可以将接口拆分为PrintableScanner

public interface Printable {
    void print();
}

public interface Scanner {
    void scan();
}

public class MultiFunctionDevice implements Printable, Scanner {
    @Override
    public void print() {
        System.out.println("Printing...");
    }

    @Override
    public void scan() {
        System.out.println("Scanning...");
    }
}

public class PrinterOnlyDevice implements Printable {
    @Override
    public void print() {
        System.out.println("Printing only...");
    }
}

好处:

  • 减少不必要的依赖。
  • 提高接口的清晰性和专一性。

6. 迪米特法则(最少知道原则)

定义:迪米特法则提倡一个对象应该对其它对象有尽可能少的了解,即如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用;如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
例子: 避免一个对象直接访问另一个对象的内部状态,而是通过方法调用来获取所需信息。

public class Student {
    private String name;
    private Address address;

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

    public String getName() {
        return name;
    }

    public Address getAddress() {
        return address;
    }

    public String getCity() {
        return address.getCity();
    }
}

public class Address {
    private String city;

    public Address(String city) {
        this.city = city;
    }

    public String getCity() {
        return city;
    }
}

好处:

  • 降低耦合度。
  • 增加代码的可读性和可维护性。

四、结论

遵循这些设计原则有助于开发出更加灵活、可靠且易于维护的软件系统,虽然有时候遵循这些原则可能会带来一些额外的工作量,但从长远来看,这绝对是值得的。在实际应用中,可以根据项目的需求和特点灵活地选择和应用这些原则~~

  • 25
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值