[23 Design Patterns] Opening and Closing Principle

Personal homepage:Golden Scales Stepping on the Rain

Personal introduction: Hello everyone, I amJinlin, a fledgling Java novice< /span>

Current situation: A 22nd ordinary undergraduate graduate. After many twists and turns, he now works for a large and well-known domestic daily chemical company, engaged in Java development

My blog: This is CSDN, where I learn technology and summarize knowledge. I hope to communicate with you and make progress together ~

This article is from Douyin's "IT Nan Teacher" design pattern course. The following are some of my learning experiences based on the original courseware.

1. Overview of principles

Open Closed Principle, abbreviated as OCP. Software entities (modules, classes, methods, etc.) should be "open for extension and closed for modification". An obvious example is——Strategy Design Pattern

Open for extension, closed for modification.

When we need to add a new function, we should extend the code based on the existing code (add new modules, classes, methods etc.), rather than modifying existing code (modifying modules, classes, methods, etc.).

The opening and closing principle does not prevent us from modifying the code, but allows us to try to avoid "overhauling and overhauling". Design patterns are methods and routines, and are not" ;Shackles"! ! !

case analysis

problem code

The following is an example in a common production environment. We will show a simplifiedorder discount strategy for an e-commerce platform. Can the following code comply with the definition of the opening and closing principle?

class Order {
    private double totalAmount;

    public Order(double totalAmount) {
        this.totalAmount = totalAmount;
    }

    // 计算折扣后的金额
    public double getDiscountedAmount(String discountType) {
        double discountedAmount = totalAmount;

        if (discountType.equals("FESTIVAL")) {
            discountedAmount = totalAmount * 0.9; // 节日折扣,9折
        } else if (discountType.equals("SEASONAL")) {
            discountedAmount = totalAmount * 0.8; // 季节折扣,8折
        }

        return discountedAmount;
    }
}

In the above code, the Order class contains a method for calculating the discount amount, which applies discounts according to different discount types. When we needadd a new discount type, wehave to modifygetDiscountedAmount() The code of the method is obviously unreasonable, which violates the opening and closing principle< /span>.

optimization

abstract interface

// 抽象折扣策略接口
interface DiscountStrategy {
    double getDiscountedAmount(double totalAmount);
}

specific strategies

// 节日折扣策略
class FestivalDiscountStrategy implements DiscountStrategy {
    @Override
    public double getDiscountedAmount(double totalAmount) {
        return totalAmount * 0.9; // 9折
    }
}

// 季节折扣策略
class SeasonalDiscountStrategy implements DiscountStrategy {
    @Override
    public double getDiscountedAmount(double totalAmount) {
        return totalAmount * 0.8; // 8折
    }
}
class Order {
    private double totalAmount;
    private DiscountStrategy discountStrategy;

    public Order(double totalAmount, DiscountStrategy discountStrategy) {
        this.totalAmount = totalAmount;
        this.discountStrategy = discountStrategy;
    }

    public void setDiscountStrategy(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    // 计算折扣后的金额
    public double getDiscountedAmount() {
        return discountStrategy.getDiscountedAmount(totalAmount);
    }
}

In the code that follows the open-close principle, we define an abstract discount strategy interface DiscountStrategy, and then create a A strategy class that implements this interface. The Order class uses the combination method and contains a member variable of type DiscountStrategy to set or change the discount at runtime. Strategy, (can be through coding, configuration, dependency injection, etc.).

In this way,when we need to add a new discount type, we only need to implement the DiscountStrategy interface without modifying the existing Order code. This example follows the open-closed principle.

2. Does modifying the code mean violating the open-close principle?

The core idea of ​​the open-close principle is tominimize modifications to existing code so as to Reduce the risk and impact of modifications. In the actual development process, it is unrealistic to not modify the code at all! When requirements change or errors are found in the code, it is normal to modify the code. However, the open-closed principle encourages us to design better code structures so that when adding new features or expanding the system, we can minimize the impact on existing code. Revise.

case analysis

The following is a simplified logger example that demonstrates how to modify the code where appropriate without violating the open-closed principle.

In this example, our application supports logging to the console and to a file. Suppose we need to add a new feature that adds a timestampwhile outputting the log.

original code

interface Logger {
    void log(String message);
}

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

class FileLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("File: " + message);
        // 将日志写入文件的实现省略
    }
}

In order to add timestamp functionality, we needmodify the existing ConsoleLogger and FileLogger classes. Although we need to modify the code, since this is an improvement to existing functions rather than adding new functions, this modification is acceptable and does not violate the opening and closing principle.

Modified code

interface Logger {
    void log(String message);
}

class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        System.out.println("Console [" + timestamp + "]: " + message);
    }
}

class FileLogger implements Logger {
    @Override
    public void log(String message) {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        String logMessage = "File [" + timestamp + "]: " + message;
        System.out.println(logMessage);
        // 将日志写入文件的实现省略
    }
}

In this example, we just made appropriate modifications to the existing logger class to add timestamp functionality. This modification will not affect other parts of the code, so it does not violate the opening and closing principle. In short, appropriate code modifications do not necessarily violate the opening and closing principle. The key lies in how we weigh the impact of modifications and code design.

3. How to achieve "open for extension and closed for modification"?

The opening and closing principle talks about the scalability of code. It is the "gold standard" for judging whether a piece of code is easy to expand.

If a certain piece of code can be "open for expansion and closed for modification" in response to future changes in demand, it means that the scalability of this piece of code is relatively good.

Before talking about the specific methodology, let's first look at some more top-level guiding ideas. In order to write code with good scalability as much as possible, we must always have awareness of expansion, abstraction, and encapsulation. These"subconscious minds"may be more important than any development skills.

Sometimes, we need to think about the following questions:

  • What changes may be required in the future for the code I want to write and how to design the code structure?Reserve extension points in advance so that I can When requirements change in the future, new code can be flexibly inserted into the extension without changing the overall structure of the code and achieving minimal code changes Click on it and make it “open for extension, closed for modification”.
  • We also need to identify the codethe variable part and the immutable part, and encapsulate the variable part to isolate changes and provide< /span> for use by upper-layer systems. When the specific implementation changes, we only need to extend a new implementation based on the same abstract interface and replace the old implementation. The code of the upstream system hardly needs to be modified. InterfaceImmutableAbstract

It should be noted that following the opening and closing principle does not mean that the code can never be modified. In the actual development process, it is unrealistic to not modify the code at all. The goal of the open-closed principle is to minimize the risks and impacts caused by modifying the code and improve the maintainability and reusability of the code. In actual development, we should balance the degree of following the open-close principle according to project needs and expected changes.

The article ends here. If you have any questions, you can point them out in the comment area~

I hope to work hard with the big guys and see you all at the top

Thank you again for your support, friends! ! !

Guess you like

Origin blog.csdn.net/weixin_43715214/article/details/134001698