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:
- The dog products
- The dog products
- 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