Design Patterns and America - the principle of opening and closing (D)

What is the principle of opening and closing

Closed for modification, open for extension

When we add a function, it should expand on the existing functionality, rather than modify (modification module, class, method) on the existing functionality

Examples of violation of the principle of opening and closing

Here, when there is a monitoring example when an error occurs or qps reach a certain threshold of early warning

public  class the Alert {
     / ** 
     * Alarm rules can be stored in their own set 
     * / 
    Private AlertRule rule;
     // notify Class 
    Private the Notification Notification; 

    public the Alert (AlertRule rule, the Notification Notification) {
         the this .rule = rule;
         the this .notification = Notification; 
    } 

    public  void Check (String API, Long RequestCount, Long errorCount, Long durationOfSeconds) {
         Long TPS = RequestCount / durationOfSeconds;
         //tps exceeds the threshold 
        IF (tps> rule.getMatchedRule (API) .getMaxTps ()) {
             // trigger alert 
            notification.notify (NotificationEmergencyLevel.URGENCY, "..." ); 
        } 
        // error count exceeds the threshold 
        IF ( errorCount> rule.getMatchedRule (API) .getMaxErrorCount ()) {
             // alert is triggered 
            notification.notify (NotificationEmergencyLevel.SEVERE, "..." ); 
        } 
    } 
}

If you need to increase demand much more than the threshold requested time 

public  class the Alert {
     / ** 
     * Alarm rules can be stored in their own set 
     * / 
    Private AlertRule rule;
     // notify Class 
    Private the Notification Notification; 

    public the Alert (AlertRule rule, the Notification Notification) {
         the this .rule = rule;
         the this .notification = Notification; 
    } 

    // parameter changes an increase timeOutCount 
    public  void Check (String API, Long RequestCount, Long errorCount, Long timeOutCount Long durationOfSeconds) {
         LongRequestCount = TPS / durationOfSeconds;
         // TPS exceeds a threshold value 
        IF (TPS> rule.getMatchedRule (API) .getMaxTps ()) {
             // alert is triggered 
            notification.notify (NotificationEmergencyLevel.URGENCY, "..." ); 
        } 
        / / number of errors exceeds the threshold 
        IF (errorCount> rule.getMatchedRule (API) .getMaxErrorCount ()) {
             // trigger alert 
            notification.notify (NotificationEmergencyLevel.SEVERE, "..." ); 
        } 
        // change two: adding interface timeout processing logic 
        Long timeoutTps = timeoutCount / durationOfSeconds;
         IF (timeoutTps> rule.getMatchedRule(api).getMaxTimeoutTps()) {
            notification.notify(NotificationEmergencyLevel.URGENCY, "...");
        }
    }
}

Parameter changes the modifications involve changing the way we check and the original caller's

Based on the principle of opening and closing design

1. The first step is to encapsulate the class parameters

2. The second step if encapsulated by a Handle

public  class the Alert {
     // rule storage triggering an alert 
    Private List <AlertHandler> = alertHandlers new new the ArrayList <> (); 

    public  void addAlertHandler (AlertHandler alertHandler) {
         the this .alertHandlers.add (alertHandler); 
    } 

    public  void Check (ApiStatInfo apiStatInfo) {
         for (AlertHandler Handler: alertHandlers) { 
            handler.check (apiStatInfo); 
        } 
    } 
} 

/ ** 
 * parameter for packaging 
 * / 
public  class ApiStatInfo { // constructor omitted / getter / setter method
    Private String API;
     Private  Long RequestCount;
     Private  Long errorCount;
     Private  Long durationOfSeconds; 
} 

/ ** 
 * abstract parent class code reuse without repeated definition of each class member variables 
 * / 
public  abstract  class AlertHandler {
     protected AlertRule rule;
     protected the Notification Notification;
     public AlertHandler (AlertRule rule, the Notification Notification) {
         the this .rule = rule;
         the this .notification = Notification; 
    } 
    public  abstract void check(ApiStatInfo apiStatInfo);
}

/**
 * 进行tps校验通知的预警
 */
public class TpsAlertHandler extends AlertHandler {
    public TpsAlertHandler(AlertRule rule, Notification notification) {
        super(rule, notification);
    }

    @Override
    public void check(ApiStatInfo apiStatInfo) {
        long tps = apiStatInfo.getRequestCount()/ apiStatInfo.getDurationOfSeconds();
        if (tps > rule.getMatchedRule(apiStatInfo.getApi()).getMaxTps()) {
            notification.notify(NotificationEmergencyLevel.URGENCY, "...");
        }
    }
}

/**
 * 基于错误数校验通知的预警
 */
public class ErrorAlertHandler extends AlertHandler {
    public ErrorAlertHandler(AlertRule rule, Notification notification){
        super(rule, notification);
    }

    @Override
    public void check(ApiStatInfo apiStatInfo) {
        if (apiStatInfo.getErrorCount() > rule.getMatchedRule(apiStatInfo.getApi()).getMaxErrorCount()) {
            notification.notify(NotificationEmergencyLevel.SEVERE, "...");
        }
    }
}

Use of external unified front of the class talked about the exposure of the package

public  class the ApplicationContext {
     Private AlertRule alertRule;
     Private the Notification Notification;
     Private the Alert Alert; 

    / ** 
     * initialize Alert 
     * / 
    public  void initializeBeans () { 
        alertRule = new new AlertRule ( / * parameter is omitted. * / ); // omit some initialization Code 
        Notification = new new the Notification ( / * . omitted parameters * / ); // omit some initialization code 
        Alert = new new the Alert (); 
        alert.addAlertHandler (new TpsAlertHandler(alertRule, notification));
        alert.addAlertHandler(new ErrorAlertHandler(alertRule, notification));
    }
    public Alert getAlert() { return alert; }

    // 饿汉式单例
    private static final ApplicationContext instance = new ApplicationContext();
    private ApplicationContext() {
        instance.initializeBeans();
    }
    public static ApplicationContext getInstance() {
        return instance;
    }
}

public class Demo {
    public  static  void main (String [] args) { 
        ApiStatInfo apiStatInfo = new new ApiStatInfo ();
         // ... provided omitted Code apiStatInfo data values 
        ApplicationContext.getInstance () getAlert () Check (apiStatInfo);.. 
    } 
}

When we need to be modified to increase the timeout notification

public  class the Alert { // Code} unmodified ... 
public  class ApiStatInfo { // constructor omitted / getter / setter method 
  Private String API;
   Private  Long RequestCount;
   Private  Long errorCount;
   Private  Long durationOfSeconds;
   Private  Long timeoutCount; // change a : Add a new field 
}
 public  abstract  class AlertHandler { // code does not change ...} 
public  class TpsAlertHandler the extends AlertHandler { // code does not change ...}
public  class ErrorAlertHandler the extends AlertHandler { // code does not change ...}
 // two changes: Add new Handler 
public  class TimeoutAlertHandler the extends AlertHandler { // omitted codes ...} 

public  class the ApplicationContext {
   Private AlertRule alertRule;
   Private the Notification Notification;
   Private the Alert Alert; 
  
  public  void initializeBeans () { 
    alertRule = new new AlertRule ( / * parameter is omitted. * / ); // omit some initialization code
    = Notification new new the Notification ( / * parameter is omitted. * / ); // omit some initialization code 
    Alert = new new the Alert (); 
    alert.addAlertHandler ( new new TpsAlertHandler (alertRule, Notification)); 
    alert.addAlertHandler ( new new ErrorAlertHandler (alertRule, Notification));
     // three changes: Register Handler 
    alert.addAlertHandler ( new new TimeoutAlertHandler (alertRule, Notification)); 
  } 
  // ... No other changes to the code omitted ... 
} 

public  class Demo {
   public  static  void main (String [ ] args) {
    ApiStatInfo ApiStatInfo = new new ApiStatInfo ();
     // ... apiStatInfo set of field codes omitted 
    apiStatInfo.setTimeoutCount (289); // change IV: Set value tiemoutCount 
    ApplicationContext.getInstance () getAlert () Check (apiStatInfo);.. 
}

The above changes may be wondering a few points are in violation of the principle of modified closed

In fact, just above Expanding on the original function did not affect the original logic  

Although a change and change is a modification of three real-time opening and closing principle is not absolute. Although it is modified in order to inject new extension points, some modifications can not be avoided

 

How to achieve "open for extension but closed for modification."

We should always have the expansion of consciousness, consciousness abstraction, encapsulation consciousness. When writing code, we have to take the time to think about what the future may this code needs to change, how to design code structure, extension points to stay well in advance, so that when future needs change, no change in the overall structure of the code , so that with minimal changes to the code, the new code will be inserted into the flexible extension point. Many design principles, design, design patterns, all to improve the scalability of the code as the ultimate goal. In particular, the 23 classic design patterns, mostly in order to solve the scalability problem code and summed up, are based on the principle of opening and closing as the guiding principle. The method most commonly used to increase the scalability of the code are: polymorphism, dependency injection, rather than for programming, and most of the design patterns (for example, decorative, strategy, template, chain of responsibility, status) based on the interface.

For example, we want to send a message by kafa

We need to change the interface by the late abstract rocketMq only need to add the corresponding implementation class

// 这一部分体现了抽象意识
public interface MessageQueue { //... }
public class KafkaMessageQueue implements MessageQueue { //... }
public class RocketMQMessageQueue implements MessageQueue {//...}

public interface MessageFormatter { //... }
public class JsonMessageFormatter implements MessageFormatter {//...}
public class MessageFormatter implements MessageFormatter {//} ... 

public  class Demo {
   Private the MessageQueue MsgQueue; // for programming interfaces rather than based 
  public Demo (the MessageQueue MsgQueue) { // dependency injection 
    the this .msgQueue = MsgQueue; 
  } 
  
  // msgFormatter: polymorphic, dependency injection 
  public  void the sendNotification (the Notification Notification, MessageFormatter msgFormatter) {
     // ...     
  } 
}

 

Guess you like

Origin www.cnblogs.com/LQBlog/p/12125688.html