Understanding Decoupling in Business System Design: Listener, Observer, Async, Scheduling, and Messaging Patterns
The article explains why proper business system design is crucial for low‑coupling, illustrating concepts such as listener and observer patterns, asynchronous execution, scheduled tasks, and message middleware with Java code examples to show how to achieve modular, maintainable back‑end services.
Background – In many IT companies, business requirements grow complex, and a simple "One Click" button often hides numerous system interactions, data transactions, and consistency concerns that must be considered during design.
Importance of Business System Design – Low coupling (high cohesion) reduces redundancy and complexity across modules, making the system easier to maintain, extend, and test. The article uses an e‑commerce checkout flow to illustrate how multiple subsystems (user, product, order, payment, logistics, etc.) interact.
How to Decouple – The article presents several techniques:
Breaking large business processes into smaller, independent units.
Using design patterns such as Listener, Observer, asynchronous calls, scheduled tasks, and message middleware.
1.1 Listener Pattern (Java)
package com.damon.event;
import java.util.ArrayList;
import java.util.List;
public class Context {
private static List<Listener> list = new ArrayList<Listener>();
public static void addListener(Listener listener){
list.add(listener);
}
public static void removeListener(Listener listener){
list.remove(listener);
}
public static void sendMsg(Event event){
for(Listener listener : list){
listener.onChange(event);
}
}
}Event definition:
package com.damon.event;
public class Event {
public static final int INSTALLED = 1;
public static final int STARTED = 2;
public static final int RESOLVED = 3;
public static final int STOPPED = 4;
private int type;
private Object source;
public Event(int type, Object source){
this.type = type;
this.source = source;
}
public int getType(){ return type; }
public Object getSource(){ return source; }
}Listener implementation:
package com.damon.event;
public class MyListener implements Listener {
@Override
public void onChange(Event event) {
switch(event.getType()){
case Event.STARTED:
System.out.println("started...");
break;
case Event.RESOLVED:
System.out.println("resolved...");
break;
case Event.STOPPED:
System.out.println("stopped...");
break;
default:
throw new IllegalArgumentException();
}
}
}Test class to trigger the listener:
package com.damon.event;
public class EventTest {
public static void main(String[] args){
Listener listener = new MyListener();
Context.addListener(listener);
Context.sendMsg(new Event(Event.STARTED, new MyBundle()));
}
}1.2 Observer Pattern (Java)
public abstract class Observer {
protected String name;
protected Subject subject;
public Observer(String name, Subject subject){
this.name = name;
this.subject = subject;
}
public abstract void update();
} public interface Subject {
void attach(Observer observer);
void detach(Observer observer);
void notifyObservers();
void setAction(String action);
String getAction();
} public class WechatManager implements Subject {
private List<Observer> observers = new LinkedList<>();
private String action;
@Override public void attach(Observer o){ observers.add(o); }
@Override public void detach(Observer o){ observers.remove(o); }
@Override public void notifyObservers(){ for(Observer o: observers){ o.update(); } }
@Override public void setAction(String a){ this.action = a; }
@Override public String getAction(){ return action; }
} public class InWechatRoomObserver extends Observer {
public InWechatRoomObserver(String name, Subject subject){ super(name, subject); }
@Override public void update(){
System.out.println(subject.getAction() + "
" + name + "收到公告,去开会了");
}
} public class Test {
public static void main(String[] args){
WechatManager ma = new WechatManager();
InWechatRoomObserver in = new InWechatRoomObserver("tom", ma);
OutWechatRoomObserver out = new OutWechatRoomObserver("damon", ma);
ma.attach(out);
ma.attach(in);
ma.detach(out);
ma.setAction("下午三点,大家在大会议室开会");
ma.notifyObservers();
}
}1.3 Asynchronous Execution – Using Spring’s @Async annotation together with a thread‑pool executor to run long‑running tasks without blocking the caller.
package com.damon.task;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@EnableAsync
@Configuration
public class TaskPoolConfig {
@Bean("taskExecutor")
public Executor taskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(200);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("taskExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
} @Component
public class TaskService {
private Logger logger = LoggerFactory.getLogger(getClass());
@Async("taskExecutor")
public void doTaskOne(long start, String userId) throws Exception {
logger.info(" 开始做任务一 to {}", start);
Thread.sleep(new Random().nextInt(10000));
long end = System.currentTimeMillis();
logger.info("完成任务一,耗时:" + (end - start) + "毫秒");
}
}1.4 Scheduled Tasks – Using @EnableScheduling and @Scheduled to run periodic jobs, e.g., ETL or data‑consistency checks.
@EnableAsync
@Configuration
public class TaskPoolConfig implements AsyncConfigurer {
@Bean("asyncTask")
public Executor taskExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(200);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("asyncTask-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
@Override public Executor getAsyncExecutor(){ return null; }
@Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler(){ return null; }
} @Component
public class TaskSchedule {
@Scheduled(cron = "0 * * * * ?")
public void dynamicResourceListener(){
logger.info("resourceLimitHandle timer start");
String namespace = env.getProperty("INFERENCE_JOB_NAMESPACE");
resourceListenerCallBack(namespace);
}
private void resourceListenerCallBack(String namespace){ }
}1.5 Message Middleware – Discusses using Redis, RocketMQ, RabbitMQ, Zookeeper, etc., to decouple services, implement distributed locks, and handle asynchronous communication.
Overall, the article demonstrates that thoughtful system design, leveraging patterns and asynchronous mechanisms, is essential for building scalable, maintainable back‑end applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
