Re learn the Java design mode: the actual observer mode "simulates the index lottery process similar to the passenger car, listens to the message and notifies the user of the winning lot scenario"

Little brother Fu 2021-08-07 22:08:56 阅读数:184

本文一共[544]字,预计阅读时长:1分钟~
learn java design mode actual

One 、 Preface

The more you know, the more you don't know

The knowledge of programming is endless , Like before, you dare to say that you are proficient in Java, Later I learned more and more, just want to write to understand Java, After a few years, I may want to understand a little bit Java. When the vision and pattern expand , Will let us more and more discover the original view is how simple , It's like looking at the earth from the earth and looking at the earth from the universe . But it is because of the improvement of our mind and vision that we have more understanding , And gradually learned more skills . Although I don't know more and more , But it also fills itself with more technology stacks , Make yourself stronger and stronger .

The inertia of refusing to learn is terrible

Now it's not the same as before , More information 、 There are many ways , There are also a lot of advertisements in between . This makes it difficult for many beginners to find the knowledge they want , Finally, I see that some people recommend relevant learning materials and immediately block them 、 Delete , But you can't see good technology at the same time . Over time, I put more time and energy into the game 、 entertainment 、 On the video , Proper relaxation is OK , But it's hard to come out after indulging in it , So you need to make some plans for your growth , A little restraint .

Balance the cost of software design and implementation °

Sometimes a software architecture design needs to meet the current conditions of the various factors , Often can't because the heart takes for granted a blueprint , Just go and start the execution . Maybe even though your design is excellent , But in the current environment, it is difficult to meet the time requirements of the business , When the basic demands of a business cannot be met , It's hard to pull the market . No product DAU brace , In the end, the whole R & D project will be stagnant . But R & D can't write code in a mess , So we need to find a suitable degree , For example, we can build a good foundation , Extensible in implementation . But in terms of specific functions, we can simplify the implementation first , Continue to refine iterations as you survive .

Two 、 development environment

  1. JDK 1.8
  2. Idea + Maven
  3. Three projects are involved , You can pay attention to the official account. : bugstack Wormhole stack , Reply to source code download ( Open the acquired link , Find the serial number 18)
engineering describe
itstack-demo-design-18-00 Scene simulation engineering ; Simulate a minibus lottery interface
itstack-demo-design-18-01 Use a bunch of code to achieve business requirements
itstack-demo-design-18-02 Modify code through design pattern optimization , Create contrast to learn

3、 ... and 、 Introduction to observer mode

 Observer mode , The picture is from refactoringguru.cn

Simply put, the observer ???? Pattern , When a behavior occurs, it transmits information to another user, receives it and makes corresponding processing , There is no direct coupling between the two . for example ; The sniper 、 Li Yunlong .

 Li Yunlong gives you a thumbs up

Besides the scenes in life , In our programming development, we will often use some observer patterns or components , For example, we often use MQ service , although MQ Service has a notification center, not every class service notifies , But on the whole, it can also be regarded as the design of the observer mode . For example, there may be some similar event monitoring buses that have been done , Separate the main line service from other auxiliary line business services , In order to reduce the coupling and enhance the scalability of the system , You'll also use observer mode for processing .

Four 、 Simulation scenarios

 Scene simulation ; Small bus indicator lottery notification scene

In this case, we simulate the scene of each event notification of passenger car index lottery ( The real news will not be sent to you by the official website )

Maybe most people will think of the scene that they won't hit each time when they see this case , Received a sorry SMS notification . Of course, the current lottery system doesn't text you , It's a text message sent by Baidu or some other plug-ins . So if this similar lottery function is developed by you , In addition, we need to notify the external users of the event and add some additional auxiliary processes outside the main process ?

Basically, many people have rough implementation of such notification event class , Add... Directly to the class .1 It's about thinking about ???? This may not expand much ,2 I didn't think about it at all ???? too . But if you think about your core class functions, you'll find , There are some core main links , And then there's the auxiliary function . For example, after completing a certain behavior, you need to trigger MQ Externally , And do some news PUSH For users, etc , These are not core process links , Events can be handled by notification .

Then we use this design pattern to optimize and refactor the code in this scenario .

1. Scene simulation engineering

itstack-demo-design-18-00
└── src
└── main
└── java
└── org.itstack.demo.design
└── MinibusTargetService.java
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • What is provided here is a service interface that simulates the lottery number of a small bus .

2. Scenario description

2.1 Lottery service interface

public class MinibusTargetService {
/**
* Simulation of the lottery , But it's not a lottery algorithm
*
* @param uId The user id
* @return result
*/
public String lottery(String uId) {
return Math.abs(uId.hashCode()) % 2 == 0 ? " congratulations , code ".concat(uId).concat(" In this lottery ") : " unfortunately , code ".concat(uId).concat(" In this lottery, the lottery does not win or the lottery qualification has expired ");
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • A very simple analog lottery interface , It's different from the real and fair lottery .

5、 ... and 、 With a lump of code to achieve

Here we use the most crude way to achieve the function

Add it to the original lottery interface as required MQ Message sending and SMS notification function , If it is the most direct way, you can directly add functions to the method .

1. Engineering structure

itstack-demo-design-18-01
└── src
└── main
└── java
└── org.itstack.demo.design
├── LotteryResult.java
├── LotteryService.java
└── LotteryServiceImpl.java
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • This code interface includes three parts ; Returns the object (LotteryResult)、 Defining interfaces (LotteryService)、 Concrete realization (LotteryServiceImpl).

2. Code implementation

public class LotteryServiceImpl implements LotteryService {
private Logger logger = LoggerFactory.getLogger(LotteryServiceImpl.class);
private MinibusTargetService minibusTargetService = new MinibusTargetService();
public LotteryResult doDraw(String uId) {
// Swaying
String lottery = minibusTargetService.lottery(uId);
// texting
logger.info(" To the user {} Send SMS notification ( SMS ):{}", uId, lottery);
// Hair MQ news
logger.info(" Record user {} The lottery result (MQ):{}", uId, lottery);
// result
return new LotteryResult(uId, lottery, new Date());
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • As can be seen from the above method implementation , The whole process consists of three parts ; Swaying 、 texting 、 Hair MQ news , And this part is called sequentially .
  • In addition to the Yaohao interface call , The latter two parts are non core main link functions , And will continue to adjust and expand with the development of subsequent business requirements , In this way, it's very difficult to maintain .

3. Test verification

3.1 Writing test classes

@Test
public void test() {
LotteryService lotteryService = new LotteryServiceImpl();
LotteryResult result = lotteryService.doDraw("2765789109876");
logger.info(" test result :{}", JSON.toJSONString(result));
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • In the test process, the call to the lottery service interface is provided .

3.2 test result

22:02:24.520 [main] INFO o.i.demo.design.LotteryServiceImpl - To the user 2765789109876 Send SMS notification ( SMS ): unfortunately , code 2765789109876 In this lottery, the lottery does not win or the lottery qualification has expired
22:02:24.523 [main] INFO o.i.demo.design.LotteryServiceImpl - Record user 2765789109876 The lottery result (MQ): unfortunately , code 2765789109876 In this lottery, the lottery does not win or the lottery qualification has expired
22:02:24.606 [main] INFO org.itstack.demo.design.ApiTest - test result :{"dateTime":1598764144524,"msg":" unfortunately , code 2765789109876 In this lottery, the lottery does not win or the lottery qualification has expired ","uId":"2765789109876"}
Process finished with exit code 0
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • From the test results are in line with expectations , It's also the usual way to develop code , It's very simple .

6、 ... and 、 Observer pattern refactoring code

Next, use observer mode to optimize the code , It's a very small refactoring .

1. Engineering structure

itstack-demo-design-18-02
└── src
└── main
└── java
└── org.itstack.demo.design
├── event
│ ├── listener
│ │ ├── EventListener.java
│ │ ├── MessageEventListener.java
│ │ └── MQEventListener.java
│ └── EventManager.java
├── LotteryResult.java
├── LotteryService.java
└── LotteryServiceImpl.java
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

Observer pattern model structure

 Observer pattern model structure

  • From the picture above, it can be divided into three parts ; Event monitoring 、 Event handling 、 Specific business process , In addition, in the business process LotteryService It defines abstract classes , Because this can shield the event function through the abstract class , External business process developers don't need to know the specific notification operation .
  • The circle chart in the lower right corner shows the structure of core process and non core process , Generally, in the development process, the main line process will be developed after , Then use notification to handle auxiliary processes . They can be asynchronous , stay MQ And the processing of timed tasks , Ensure ultimate consistency .

2. Code implementation

2.1 Event listening interface definition

public interface EventListener {
void doEvent(LotteryResult result);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • The basic event class is defined in the interface , Here, if the input information type of the method is variable, you can use generics <T>

2.2 Implementation of two listening Events

SMS event

public class MessageEventListener implements EventListener {
private Logger logger = LoggerFactory.getLogger(MessageEventListener.class);
@Override
public void doEvent(LotteryResult result) {
logger.info(" To the user {} Send SMS notification ( SMS ):{}", result.getuId(), result.getMsg());
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

MQ Send events

public class MQEventListener implements EventListener {
private Logger logger = LoggerFactory.getLogger(MQEventListener.class);
@Override
public void doEvent(LotteryResult result) {
logger.info(" Record user {} The lottery result (MQ):{}", result.getuId(), result.getMsg());
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • These are the concrete implementations of the two events , It's relatively simple . If it is the actual business development, it will need to call the external interface and control the exception handling .
  • At the same time, we mentioned that event interfaces add generics , If necessary, the event content can be wrapped according to different types in the event implementation .

2.3 Event handling class

public class EventManager {
Map<Enum<EventType>, List<EventListener>> listeners = new HashMap<>();
public EventManager(Enum<EventType>... operations) {
for (Enum<EventType> operation : operations) {
this.listeners.put(operation, new ArrayList<>());
}
}
public enum EventType {
MQ, Message
}
/**
* subscribe
* @param eventType Event type
* @param listener monitor
*/
public void subscribe(Enum<EventType> eventType, EventListener listener) {
List<EventListener> users = listeners.get(eventType);
users.add(listener);
}
/**
* Unsubscribe
* @param eventType Event type
* @param listener monitor
*/
public void unsubscribe(Enum<EventType> eventType, EventListener listener) {
List<EventListener> users = listeners.get(eventType);
users.remove(listener);
}
/**
* notice
* @param eventType Event type
* @param result result
*/
public void notify(Enum<EventType> eventType, LotteryResult result) {
List<EventListener> users = listeners.get(eventType);
for (EventListener listener : users) {
listener.doEvent(result);
}
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • The implementation of the whole process provides three main methods ; subscribe (subscribe)、 Unsubscribe (unsubscribe)、 notice (notify). These three methods are used to add and use the monitoring time respectively .
  • And because there are different types of events , The enumeration method is used here , It is also convenient for the external to use the event under the regulations , It's not about spreading information (EventType.MQ、EventType.Message).

2.4 Business abstract class interface

public abstract class LotteryService {
private EventManager eventManager;
public LotteryService() {
eventManager = new EventManager(EventManager.EventType.MQ, EventManager.EventType.Message);
eventManager.subscribe(EventManager.EventType.MQ, new MQEventListener());
eventManager.subscribe(EventManager.EventType.Message, new MessageEventListener());
}
public LotteryResult draw(String uId) {
LotteryResult lotteryResult = doDraw(uId);
// Call whatever method you need to be notified
eventManager.notify(EventManager.EventType.MQ, lotteryResult);
eventManager.notify(EventManager.EventType.Message, lotteryResult);
return lotteryResult;
}
protected abstract LotteryResult doDraw(String uId);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • This uses abstract classes to define implementation methods , You can extend the extra calls you need in a method . And provide abstract classes abstract LotteryResult doDraw(String uId), Let the class's inheritors implement .
  • At the same time, the definition of method uses protected, That is to ensure that external callers will not call this method in the future , Only call to draw(String uId), So that we can complete the event notification .
  • The implementation of this way is to write a basic method in the abstract class , At the same time of completing the new logic in the method , Add the use of abstract classes . The definition of this abstract class will be implemented by inheritors .
  • In addition, the definition of events is provided in the constructor ;eventManager.subscribe(EventManager.EventType.MQ, new MQEventListener()).
  • When using, it also uses the enumeration method for notification , What kind of transmission EventManager.EventType.MQ, What event notification will be executed , Add... As needed .

2.5 Business interface implementation class

public class LotteryServiceImpl extends LotteryService {
private MinibusTargetService minibusTargetService = new MinibusTargetService();
@Override
protected LotteryResult doDraw(String uId) {
// Swaying
String lottery = minibusTargetService.lottery(uId);
// result
return new LotteryResult(uId, lottery, new Date());
}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • Now look at the implementation of the business process, you can see that it is very simple , There is no additional auxiliary process , Only the handling of the core process .

3. Test verification

3.1 Writing test classes

@Test
public void test() {
LotteryService lotteryService = new LotteryServiceImpl();
LotteryResult result = lotteryService.draw("2765789109876");
logger.info(" test result :{}", JSON.toJSONString(result));
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • There's almost no difference in terms of calls , But this way of implementation can be very convenient to maintain the code and expand new requirements .

3.2 test result

23:56:07.597 [main] INFO o.i.d.d.e.listener.MQEventListener - Record user 2765789109876 The lottery result (MQ): unfortunately , code 2765789109876 In this lottery, the lottery does not win or the lottery qualification has expired
23:56:07.600 [main] INFO o.i.d.d.e.l.MessageEventListener - To the user 2765789109876 Send SMS notification ( SMS ): unfortunately , code 2765789109876 In this lottery, the lottery does not win or the lottery qualification has expired
23:56:07.698 [main] INFO org.itstack.demo.design.test.ApiTest - test result :{"dateTime":1599737367591,"msg":" unfortunately , code 2765789109876 In this lottery, the lottery does not win or the lottery qualification has expired ","uId":"2765789109876"}
Process finished with exit code 0
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • From the test results, we can see that ???? Our expectations , Although the results are the same , But only we know the charm of design patterns .

7、 ... and 、 summary

  • From our most basic procedural development and later object-oriented development using the observer pattern , You can see that after the design pattern has been transformed , The code of core process and auxiliary process is separated . The core processes in general code don't change very often . But ancillary processes change with the business , Include ; marketing 、 fission 、 Promoting activity, etc , Therefore, it is necessary to use design patterns to set up code .
  • This kind of design pattern satisfies the principle of opening and closing from the structure , When you need to add other listening events or modify the monitoring logic , There is no need to change the event handling class . However, you may not be able to control the order of calls and you need to do something to return the result of the event , So we need to consider the rationality of the scene when using the process .
  • No design pattern is used alone sometimes , It needs to be built in combination with other modes . In addition, design patterns are used to make code easier to expand and maintain , You can't make the structure more complex and difficult to maintain by adding design patterns . This kind of rational use experience requires a lot of practical practice .
版权声明:本文为[Little brother Fu]所创,转载请带上原文链接,感谢。 https://car.inotgo.com/2021/08/20210807220624140b.html