# 设计模式
设计模式(Design pattern)代表了**最佳的实践**,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中**面临的一般问题的解决方案**。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
大部分的设计模式都是为了实现**高内聚,低耦合**。
## 观察者模式(ObserverPattern)
定义对象之间的一种一对多依赖关系,使得每一个对象发生状态的变化时,其相关依赖对象皆得到通知并被自动更新,又称为发布-订阅模式、模型-视图模式、源-监听器模式或从属者模式。
当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知依赖它的对象。
观察者模式共分为四种角色:
- Subject(目标类):被观察的对象,内部定义一个观察者集合,并提供管理方法,定义通知方法notify()。
- ConcreteSubject(具体目标类):继承目标类,实现notify中具体的方法,可省略。
- Observer(观察者):对目标类做出的变化进行反应,一般为接口,声明更新方法update()。
- ConcreteObserver(具体观察者):继承观察者,一般持有指向具体目标类的引用,实现update方法,调用具体 目标类完成具体的业务操作。
> 小例子:产品去甲方那边开会了解甲方的需求,回来后把开会内容整理成需求告诉开发人员,开发人员按各自的职责去做不同的事情。
### 样例
#### 阿里云云效代码大赛(2020.10.24)第一题
> 生存舱有一个智慧农业的控制系统,该系统能根据温度、湿度、风力的变化来控制各种设备。为了让因灾害而失去家园的人们尽早地有能力自给自足,我们需要给这个系统添加新的设备。但是现在系统已经受损,无法在添加新设备时保证不影响原有功能。这个任务就交给你啦。
```java
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();
}
}
public class WateringMachine {
private boolean status;
public boolean getStatus() {
return status;
}
public void start() {
status = true;
}
}
```
重构为观察者模式:
```java
public interface Machine{
void onChange(int temp, int humidity, int windPower);
}
public class ReapingMachine implements Machine {
private boolean status;
private static final int tempThreshold = 5;
private static final int humidityThreshold = 65;
public boolean getStatus() {
return status;
}
public void start() {
status = true;
}
public void onChange(int temp, int humidity, int windPower) {
if (temp > tempThreshold && humidity > humidityThreshold) {
this.start();
}
}
}
public class WeatherData {
private List<Machine> machines;
public WeatherData(Machine... machines){
this.machines = Arrays.asList(machines);
}
public void measurementsChanged(int temp, int humidity, int windPower) {
this.machines.forEach(machine-> machine.onChange(temp,humidity,windPower));
}
}
```
### 优缺点
- 优点
- 观察者和被观察者是抽象耦合(低耦合)的。
- 符合开闭原则
- 业务内容相对独立
- 缺点
- 当观察者有很多的时候,通知成本会很高。
- 没有机制让观察者知道对象是怎么发生变化的。
## 模板方法模式(StrategyPattern)
在模板模式中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以**按需要重写方法实现,但调用将以抽象类中定义的方式进行**。这种类型的设计模式属于行为型模式。
将一系列方法中的固定方法提取到抽象层,完成代码的复用,且通过子类的重写行为改变类的模板方法的功能的改变。
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
> 小例子:很多同学在做PPT的时候就是找一个PPT模板改一改文字内容就完成了PPT的制作,不需要关心PPT动画,不需要关心PPT的颜色。
### 样例
像前端开发中的组件化概念以及面向对象语言中的继承概念,都是模板方法的体现。
实现MongoDB数据库的统一的逻辑删除控制:
```java
public abstract class BaseDocument implements Serializable {
private String id;
@JsonIgnore
private Long deleteFlag = 0L;
private Long createTime;
private Long updateTime;
....
}
public interface MjolnirMongoService<T extends BaseDocument> {
MongoTemplate getTemplate();
Class<T> getClazz();
default T getById(String id) throws MjolnirServiceException {
if (StrUtil.isBlank(id)) {
throw new MjolnirServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "传入参数为空");
}
T t = getTemplate().findById(id, getClazz());
if (t == null || t.isDelete()) {
throw new MjolnirServiceException(TyrfingErrorCode.DATA_NOT_FOUND, "数据不存在");
}
return t;
}
//......
default MjolnirPage<T> page(int current, int size, Query query) {
query.addCriteria(Criteria.where("deleteFlag").is(0L));
//......
}
default T save(T t) throws MjolnirServiceException {
if (t == null) {
throw new MjolnirServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "传入参数为空");
}
if (StrUtil.isBlank(t.getId())) {
return insert(t);
}
if (getById(t.getId()).isDelete()) {
throw new MjolnirServiceException(TyrfingErrorCode.ILLEGAL_OPERATION, "禁止的操作");
}
t.setUpdateTime(System.currentTimeMillis());
return getTemplate().save(t);
}
default T insert(T t) throws MjolnirServiceException {
if (t == null) {
throw new MjolnirServiceException(TyrfingErrorCode.LACK_OF_PARAMETER, "传入参数为空");
}
if (StrUtil.isNotEmpty(t.getId()) || t.isDelete()) {
throw new MjolnirServiceException(TyrfingErrorCode.ILLEGAL_OPERATION, "禁止的操作");
}
t.setDeleteFlag(0L);
t.setCreateTime(System.currentTimeMillis());
t.setUpdateTime(System.currentTimeMillis());
return getTemplate().save(t);
}
default T getOne(Query query) throws MjolnirServiceException {
query.addCriteria(Criteria.where("deleteFlag").is(0L));
//......
}
default T remove(String id) throws MjolnirServiceException {
//......
T t = getById(id);
t.setDeleteFlag(System.currentTimeMillis());
return getTemplate().save(t);
}
default Long count(Query query) {
query.addCriteria(Criteria.where("deleteFlag").is(0L));
return getTemplate().count(query, getClazz());
}
}
@Service
public class TestServiceImpl implements MjolnirService<Test> {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public MongoTemplate getTemplate() {
return mongoTemplate;
}
@Override
public Class<Test> getClazz() {
return Test.class;
}
}
```
推荐阅读:[#设计模式 ](https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzU3OTc1MDM1Mg==&action=getalbum&album_id=1602246395342667777&scene=173&from_msgid=2247494096&from_itemidx=3&count=3#wechat_redirect)
观察者模式&模板方法模式