Spring中使用设计模式(二、观察者模式)
观察者模式是行为类模式的一种,可以解耦发布和订阅。本文结合前几天阿里的今年83行代码重构大师赛题目说明。
观察者模式
题目:生存舱有一个智慧农业的控制系统,该系统能根据温度、湿度、风力的变化来控制各种设备。为了让因灾害而失去家园的人们尽早地有能力自给自足,我们需要给这个系统添加新的设备。但是现在系统已经受损,无法在添加新设备时保证不影响原有功能。
这个任务就交给你啦 你的任务:用观察者模式重构系统的代码,使添加新设备时不用担心影响原有功能(符合开闭原则)。
public class WeatherData {
private SeedingMachine seedingMachine;
private ReapingMachine reapingMachine;
private WateringMachine wateringMachine;
public WeatherData(SeedingMachine seedingMachine, ReapingMachine reapingMachine, WateringMachine wateringMachine){
this.seedingMachine = seedingMachine;
this.reapingMachine = reapingMachine;
this.wateringMachine = wateringMachine;
}
public void measurementsChanged(int temp, int humidity, int windPower)
{
if (temp > 5) {
seedingMachine.start();
if (humidity > 65)
reapingMachine.start();
}
if (temp > 10 && humidity < 55 && windPower < 4)
wateringMachine.start();
}
}
数据的变动与智慧农业的控制系统的监控处理是两件事,最好不要写在一起,用事件触发即可。
代码没有单测覆盖,先补单测,测试代码,具体如下:
@RunWith(SpringRunner.class)
@SpringBootTest
class SpringPattenTest {
@Autowired
SeedingMachine seedingMachine;
@Autowired
WeatherData weatherData;
@Test
void should_get_seedingMachine_started_when_temp_Over_5() {
boolean isOpen = seedingMachine.getStatus();
assertEquals(false,isOpen);
weatherData.measurementsChanged(6,0,0);
isOpen = seedingMachine.getStatus();
assertEquals(true,isOpen);
}
}
重思路,weatherData变化作为事件,只需要让上下文发布者通知各监听器即可。环境变化为事件类:
@Component
public class WeatherData extends ApplicationEvent {
private int temp =0;
private int humidity=0;
private int windPower=0;
public WeatherData(ApplicationContext source) {
super(source);
}
@Autowired
MyPublisher myPublisher;
public void measurementsChanged(int temp, int humidity, int windPower) {
this.temp = temp;
this.humidity = humidity;
this.windPower = windPower;
myPublisher.publisherEvent(this);
}
public int getTemp() {
return temp;
}
}
上下文发布者发布事件。
@Component
public class MyPublisher implements ApplicationContextAware{
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void publisherEvent(WeatherData myEvent) {
System.out.println("---开始发布 myEvent 事件---");
applicationContext.publishEvent(myEvent);
}
}
监听者可以有多个,每个实现具体的触发条件就好。
@Component
public class SeedingMachine implements ApplicationListener<WeatherData> {
private boolean isOpen;
public boolean getStatus() {
return isOpen;
}
@Override
public void onApplicationEvent(WeatherData weatherData) {
if (weatherData.getTemp() > 5) {
this.isOpen= true;
}
}
}
后续智慧农业的控制系统有多种不同逻辑的机器,只增加机器类即可。后续,不同逻辑的机器类可以抽出同一个接口,方便管理。
jdk也提供观察者模式,但已经使用了Spring,这种方式的观察者模式用起来也挺方便。
在实际项目中,servletListener对请求进行拦截、主题订阅等可以用本模式。