中介者模式让多对多的复杂引用关系变成一对多,同时能通过中间类来封装多个类中的行为,观察者模式在目标状态更新时能自动通知给订阅者,模版方法模式则是控制方法的执行顺序,子类在不改变算法的结构基础上可以扩展功能实现。
1 中介者模式
需求:1)系统中对象之间存在复杂的引用关系,比如一对多,多对多等。系统结构耦合度很高,结构混乱且难以理解。2)想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。在中间类中定义对象交互的公共行为。
1.1 中介者模式介绍
用一个中介对象来封装一系列的对象交互。使得各个对象不需要显式地相互引用,从而使其耦合度松散,而且可以独立地改变它们之间的交互。
图 中介者模式 UML
需求描述:在前端开发中,有三个组件 Button、View, 及Text. View 用来展示信息,Text 用于输入编辑信息,Button用来提交更新。用户在Text输入好内容后,点击Button后,内容会更新到View. 而点击View时,会把内容输入到Text。
图 需求分析图
图 需求分析UML
public class NoMediatorPattern {
public static void main(String[] args) {
Text text = new Text();
Button button = new Button();
View view = new View();
button.setText(text);
button.setView(view);
view.setText(text);
button.click();
view.click();
button.click();
}
private static class Button {
private Text text;
private View view;
public void setText(Text text) {
this.text = text;
}
public void setView(View view) {
this.view = view;
}
void click() {
if (text != null && view != null) {
view.onRefresh(text.generateText());
}
}
}
private static class Text {
private String content;
private String generateText() {
if (content == null) content = "";
Random random = new Random();
content += random.nextInt();
return content;
}
void onRefresh(String text) {
content = text;
}
}
private static class View{
private Text text;
private String content;
public void setText(Text text) {
this.text = text;
}
void click() {
if (text != null) {
text.onRefresh(content);
}
}
void onRefresh(String text) {
this.content = text; // 更新信息
System.out.println("View中显示信息:" + text);
}
}
}
上面代码中,需要考虑Button 与 Text、View,View 与Text 的交互。这使得系统逻辑变得更复杂。
图 中介者模式思维下的需求分析
图 中介者模式思维下的 UML
中介者模式下,只需要考虑中介者与各同事类的交互。
public class MediatorPattern {
public static void main(String[] args) {
Mediator mediator = new ContentMediator();
Component text = new Text(mediator, "text");
Component button = new Button(mediator,"button");
Component view = new View(mediator,"view");
mediator.registry(text);
mediator.registry(button);
mediator.registry(view);
button.onClick();
button.onClick();
view.onClick();
button.onClick();
}
private static abstract class Mediator {
protected final Set<Component> components = new HashSet<>();
public void registry(Component component) {
if (component != null) {
components.add(component);
}
}
abstract void update(String content,String target);
}
private static class ContentMediator extends Mediator{
@Override
public void update(String content,String target) {
if (content == null) {
Text text = getText();
if (text == null) throw new RuntimeException("没有更新内容");
content = text.getContent();
}
for (Component component : components) {
if (component.getTag().equals(target)) {
component.onRefresh(content);
}
}
}
private Text getText() {
for (Component component : components) {
if ("text".equals(component.getTag())) return (Text) component;
}
return null;
}
}
private static abstract class Component {
protected final Mediator mediator;
private final String tag;
protected Component(Mediator mediator, String tag) {
this.mediator = mediator;
this.tag = tag;
}
public String getTag() {
return tag;
}
abstract void onClick();
abstract void onRefresh(String content);
}
private static class Text extends Component {
private String content;
protected Text(Mediator mediator, String tag) {
super(mediator, tag);
}
@Override
void onClick() { // 输入操作
throw new RuntimeException("暂不支持Text的点击事件");
}
@Override
void onRefresh(String content) {
this.content = content;
}
public String getContent() {
Random random = new Random();
String temp = content;
if (temp == null) temp = "";
temp += random.nextInt() + "@";
content = null;
return temp;
}
}
private static class View extends Component {
private String content;
protected View(Mediator mediator, String tag) {
super(mediator, tag);
}
@Override
void onClick() {
mediator.update(content,"text");
}
@Override
void onRefresh(String content) {
this.content = content;
System.out.println("view更新:"+ content);
}
}
private static class Button extends Component {
protected Button(Mediator mediator, String tag) {
super(mediator, tag);
}
@Override
void onClick() {
mediator.update(null,"view");
}
@Override
void onRefresh(String content) {
throw new RuntimeException("暂不支持Button的更新操作");
}
}
}
1.2 优缺点
优点:
- 简化了对象之间的交互,将原本多对多的交互改成一对多。使得对象之间解耦。
- 可以通过中介者类来扩展对象的交互行为,当需要添加或改变交互行为时,只需要添加对应的中介者子类即可,符合开闭原则。
- 同事类可以更专注自身业务,而不必关心与其他同事类的交互。
缺点:
- 中介者类包含同事类之间大量的交互细节,使得该类变得非常复杂,不符合单一职责原则。
- 中介者类与同事类的耦合度高。
2 观察者模式
需求:当目标更新时,能自动通知给订阅者。
2.1 观察者模式介绍
当目标对象的状态发生改变时,它的所有观察者都会收到通知。
图 观察者模式 UML
public class ObserverPattern {
public static void main(String[] args) {
Subject subject = new School();
Observer observer1 = new Teacher();
Observer observer2 = new Student();
subject.attach(observer1);
subject.attach(observer2);
subject.notifyObserverList("快高考啦!");
subject.notifyObserverList("六一放假");
}
private static abstract class Subject {
protected final Set<Observer> observerList = new HashSet<>();
public void attach(Observer observer) {
observerList.add(observer);
}
public void detach(Observer observer) {
observerList.remove(observer);
}
public void notifyObserverList(String content) {
beforeNotify(content);
for (Observer observer : observerList) observer.update(content);
afterNotify(content);
}
public abstract void beforeNotify(String content);
public abstract void afterNotify(String content);
}
private static class School extends Subject {
@Override
public void beforeNotify(String content) {
System.out.println("通知时间:" + new Date());
}
@Override
public void afterNotify(String content) {
System.out.println("通知完成");
}
}
private interface Observer {
void update(String content);
}
private static class Student implements Observer {
@Override
public void update(String content) {
if (content.contains("放假")) System.out.println("学生,耶耶耶!");
else System.out.println("学生,哦哦哦");
}
}
private static class Teacher implements Observer {
@Override
public void update(String content) {
System.out.println("老师,收到:" + content);
}
}
}
2.2 优缺点
优点:
- 当目标状态更新时,能自动发生通知给订阅者。
- 观察者与被观察者耦合度低,符合依赖倒置原则。
缺点:
- 当观察者数量较多时,通知耗时会加长。一个观察者的卡顿会影响整体执行效率
3 模版方法模式
需求:对方法的执行顺序有要求,而某些特定方法由子类去实现。例如想写排序算法,算法内部中方法的执行顺序相同,但具体排序算法由不同子类实现。
3.1 模版方法模式介绍
定义一个操作中的算法框架,将一些步骤延迟到子类中,子类在不改变算法的结构基础上重定义该算法的某些特定步骤。
图 模版方法模式 UML
public class TemplateMethodPattern {
public static void main(String[] args) {
Worker programmer = new Programmer();
programmer.work();
}
private static abstract class Worker {
public void work() {
punch("上班");
duty();
punch("下班");
}
protected abstract void duty();
protected void punch(String content) {
System.out.println("打卡:" + content);
}
}
private static class Programmer extends Worker {
@Override
protected void duty() {
System.out.println("写bug AND 解决bug");
}
}
}
3.2 优缺点
优点:
- 可以控制方法执行顺序,当要增加新的方法实现时,只需要添加特定子类。符合开闭原则及里氏替换原则。
缺点:
- 增加了类的个数。