You must have written stinky code

Let’s introduce the topic of this article with a piece of code (LAJI).

// If the registration succeeds
if(registerSuccess()){
        // Update database
        updateDataBase();
        // Send a synchronization message
        sendMsg();
        // Send the registration information to the mailbox
        sendEmail();
        // Send registration information to mobile phone
        sendMsgToPhone();
        // There will most likely be more unknown operations on registration success in the future
        xxxxx
}
Copy the code

We can’t say it’s wrong, but have you ever thought that your favorite dog product would tell you from time to time: “After registration, you must add a XXX operation for me”?

Why do you write such stinky code, and what kind of problems does it cause?

There are only three reasons:

  1. The dog products
  2. The dog products
  3. Or a fucking dog product

Is there any help?

If you have a lot of time and you’re a code freak, I think this article might give you a little pep talk. The solution is a classic design pattern — the observer pattern.

Three examples of making the Observer mode your development killer

Warm up

Defines an observer interface that constrains the behavior of all observers

Now that is the observer pattern, so is the observer, then observe the changes of some code, I think, after a statement that readers will feel a little: observer (new demands for the dog) may be more and more, so we can’t let countless watchers at random, we must define an interface that let this group of rogue with good trousers observation well, the code is as follows:

public interface Observer {

    void doEvent();
}
Copy the code

Once the observers are bound, bring in a few more observers

public class Observer1 implements Observer { protected static final Logger logger = LoggerFactory.getLogger(Observer1.class); @override public void doEvent() {logger.info(" observer 1 received notification "); }}Copy the code
public class Observer2 implements Observer { protected static final Logger logger = LoggerFactory.getLogger(Observer2.class); @override public void doEvent() {logger.info(" observer 2 received notification "); }}Copy the code
public class Observer3 implements Observer { protected static final Logger logger = LoggerFactory.getLogger(Observer3.class); @override public void doEvent() {logger.info(" observer 3 received notification "); }}Copy the code

Add an observer managed object. Who supports it? Who against?

The following class allows readers to think of it as an intermediary for observers, deciding which observers can register and which observers can removeObserver, and notifying them of changes made by the observed.

public class Observerable { private List<Observer> observerList = new ArrayList<Observer>(); public void registerObserver(Observer observer) { observerList.add(observer); } public void removeObserver(Observer observer) { observerList.remove(observer); } public void notifyAllObserver() { for (Observer observer : observerList) { observer.doEvent(); }}}Copy the code

Ok, run this code with a test case

Class ObserverableTest {@test void notifyAllObserver() {// Define Observerable Observerable = new Observerable(); // Define three observers and register Observer1 Observer1 = new Observer1(); Observer2 observer2 = new Observer2(); Observer3 observer3 = new Observer3(); observerable.registerObserver(observer1); observerable.registerObserver(observer2); observerable.registerObserver(observer3); Boolean hasNewMsg=true; if (hasNewMsg){ observerable.notifyAllObserver(); }}}Copy the code

So with that, let’s talk about the observer model

When a message happens, there are a million actions to execute, and if we solve the problem with just one class, which we can, throw all kinds of bricks on top of your code and yell at your development team leader, “Drag?” Breaking the law? While not illegal, two problems arise with such tightly coupled code:

1. Add a new requirement and you build a thick brick that becomes less and less readable. When a need is no longer needed, you need to find the brick in your memory among countless bricks, plain and boring.Copy the code

The above code solves this problem well. It encapsulates the action to be executed after each message update by one observer and stores it in the collection, so as to add and delete, and achieve decoupling and high coordination.

Don’t write your own wheel. Guava can sit in the shade

Guava already has a wheel for observer mode, so let’s take a second one to complete the observer mode.

Introduce guava dependencies

<! Guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version>  </dependency>Copy the code

Add two observers

This is guava’s traversal, just by adding the @subscribe annotation, you can listen for changes in the observed

public class Observer1 { protected static final Logger logger = LoggerFactory.getLogger(Observer1.class); @subscribe public void handler(UpdateMsg UpdateMsg) {logger.info(" Observer 1 received message, message content {}", updatemsg.getmsg ()); }}Copy the code
public class Observer2 { protected static final Logger logger = LoggerFactory.getLogger(Observer2.class); @subscribe public void handler(UpdateMsg UpdateMsg) {logger.info(" Observer 2 received a message with the content {}", updatemsg.getmsg ()); }}Copy the code

Observer Management class

public class EventBusCenter { private static EventBus eventBus = new EventBus(); Private EventBusCenter() {} Public static void register(Object observer) { eventBus.register(observer); } public static void unRegister(Object observer) { eventBus.unregister(observer); } @param updateMsg public static void notifyAll(Object updateMsg) { eventBus.post(updateMsg); }}Copy the code

The test case

class EventBusCenterTest { @Test void notifyAllTest() { UpdateMsg updateMsg=new UpdateMsg(); Updatemsg.setmsg (" Your meituantakeout has the latest order, please handle it promptly "); EventBusCenter.register(new Observer1()); EventBusCenter.register(new Observer2()); EventBusCenter.notifyAll(updateMsg); }}Copy the code

Very tired, based on Spring let the observer sit up and move

The above code always requires us to manage the observer object is really tired, fortunately we can use the Spring framework powerful IOC to complete the observer registration, the next big trick.

Define the observer interface, standardize the observer observation behavior, and make it easier for Spring to find observers

Public interface Observer {void handlerMsg(UpdateMsg MSG); }Copy the code

Add two observers

@Component public class Observer1 implements Observer { private final Logger logger = LoggerFactory.getLogger(Observer1.class); @subscribe @override public void handlerMsg(UpdateMsg MSG) {logger.info(" observer 1 received message: {}", msg.getmsg ()); }}Copy the code
/** * @component public class Observer2 implements Observer {private final Logger Logger = LoggerFactory.getLogger(Observer2.class); @Autowired private EventBus eventBus; @override @subscribe public void handlerMsg(UpdateMsg MSG) {logger.info(" Observer 2 received message: {}", msg.getmsg ()); }}Copy the code

The bean that joins EventBus

*/ @configuration Public class MyEventBusConfig {private Final Logger Logger = LoggerFactory.getLogger(MyEventBusConfig.class); @bean EventBus getEventBus(){logger.info(" load native EventBus Bean"); return new EventBus(); }}Copy the code

The observer needs to listen to the message object, the author also selected a separate object this time

Public class UpdateMsg {/** * private String MSG; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public UpdateMsg(String msg) { this.msg = msg; }}Copy the code

Big idea, add observer management class

This observer management class inherits ApplicationContextAware, which executes the following code after Spring has loaded all the beans:

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
Copy the code

This code is a bean postoperation that adds an ApplicationContext to the bean factory. Basically, after all beans are initialized, it looks for the lucky audience in the container that inherits the ApplicationContextAware. The applicationContext can be given to you to play with as much as you like. For details, see the article # HandwritingSpring Chapter 8: Defining the Aware interface for tag types and implementing Aware container objects

@Component public class EventBusMgrCenter implements ApplicationContextAware { @Autowired private EventBus eventBus; public void post(Object event) { eventBus.post(event); } public void register(Object handler) { eventBus.register(handler); } public void unregister(Object handler) { eventBus.unregister(handler); } /** * Based on the spring API's second method of registering observers, this method will be used after all beans have been initialized, * by the beanFactory addBeanPostProcessor (new ApplicationContextAwareProcessor (this)); * @param applicationContext * @throws BeansException */ @override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { Map<String, Observer> observerMap = applicationContext.getBeansOfType(Observer.class); observerMap.values().forEach(observer -> register(observer)); }}Copy the code

The source address

The first two examples: gitee.com/fugongliude… Third example: gitee.com/fugongliude…

reference

# of actual combat! Say goodbye to pipelining code and talk about common design patterns at work! The Observer model is explained in detail