• 【再探】设计模式—中介者模式、观察者模式及模板方法模式


     中介者模式让多对多的复杂引用关系变成一对多,同时能通过中间类来封装多个类中的行为,观察者模式在目标状态更新时能自动通知给订阅者,模版方法模式则是控制方法的执行顺序,子类在不改变算法的结构基础上可以扩展功能实现。

    1 中介者模式

    需求:1)系统中对象之间存在复杂的引用关系,比如一对多,多对多等。系统结构耦合度很高,结构混乱且难以理解。2)想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。在中间类中定义对象交互的公共行为。

    1.1 中介者模式介绍

    用一个中介对象来封装一系列的对象交互。使得各个对象不需要显式地相互引用,从而使其耦合度松散,而且可以独立地改变它们之间的交互。

    图 中介者模式 UML

    需求描述:在前端开发中,有三个组件 Button、View, 及Text. View 用来展示信息,Text 用于输入编辑信息,Button用来提交更新。用户在Text输入好内容后,点击Button后,内容会更新到View. 而点击View时,会把内容输入到Text。

    图 需求分析图

    图 需求分析UML

    1. public class NoMediatorPattern {
    2. public static void main(String[] args) {
    3. Text text = new Text();
    4. Button button = new Button();
    5. View view = new View();
    6. button.setText(text);
    7. button.setView(view);
    8. view.setText(text);
    9. button.click();
    10. view.click();
    11. button.click();
    12. }
    13. private static class Button {
    14. private Text text;
    15. private View view;
    16. public void setText(Text text) {
    17. this.text = text;
    18. }
    19. public void setView(View view) {
    20. this.view = view;
    21. }
    22. void click() {
    23. if (text != null && view != null) {
    24. view.onRefresh(text.generateText());
    25. }
    26. }
    27. }
    28. private static class Text {
    29. private String content;
    30. private String generateText() {
    31. if (content == null) content = "";
    32. Random random = new Random();
    33. content += random.nextInt();
    34. return content;
    35. }
    36. void onRefresh(String text) {
    37. content = text;
    38. }
    39. }
    40. private static class View{
    41. private Text text;
    42. private String content;
    43. public void setText(Text text) {
    44. this.text = text;
    45. }
    46. void click() {
    47. if (text != null) {
    48. text.onRefresh(content);
    49. }
    50. }
    51. void onRefresh(String text) {
    52. this.content = text; // 更新信息
    53. System.out.println("View中显示信息:" + text);
    54. }
    55. }
    56. }

    上面代码中,需要考虑Button 与 Text、View,View 与Text 的交互。这使得系统逻辑变得更复杂。

    图 中介者模式思维下的需求分析

    图 中介者模式思维下的 UML

    中介者模式下,只需要考虑中介者与各同事类的交互。

    1. public class MediatorPattern {
    2. public static void main(String[] args) {
    3. Mediator mediator = new ContentMediator();
    4. Component text = new Text(mediator, "text");
    5. Component button = new Button(mediator,"button");
    6. Component view = new View(mediator,"view");
    7. mediator.registry(text);
    8. mediator.registry(button);
    9. mediator.registry(view);
    10. button.onClick();
    11. button.onClick();
    12. view.onClick();
    13. button.onClick();
    14. }
    15. private static abstract class Mediator {
    16. protected final Set components = new HashSet<>();
    17. public void registry(Component component) {
    18. if (component != null) {
    19. components.add(component);
    20. }
    21. }
    22. abstract void update(String content,String target);
    23. }
    24. private static class ContentMediator extends Mediator{
    25. @Override
    26. public void update(String content,String target) {
    27. if (content == null) {
    28. Text text = getText();
    29. if (text == null) throw new RuntimeException("没有更新内容");
    30. content = text.getContent();
    31. }
    32. for (Component component : components) {
    33. if (component.getTag().equals(target)) {
    34. component.onRefresh(content);
    35. }
    36. }
    37. }
    38. private Text getText() {
    39. for (Component component : components) {
    40. if ("text".equals(component.getTag())) return (Text) component;
    41. }
    42. return null;
    43. }
    44. }
    45. private static abstract class Component {
    46. protected final Mediator mediator;
    47. private final String tag;
    48. protected Component(Mediator mediator, String tag) {
    49. this.mediator = mediator;
    50. this.tag = tag;
    51. }
    52. public String getTag() {
    53. return tag;
    54. }
    55. abstract void onClick();
    56. abstract void onRefresh(String content);
    57. }
    58. private static class Text extends Component {
    59. private String content;
    60. protected Text(Mediator mediator, String tag) {
    61. super(mediator, tag);
    62. }
    63. @Override
    64. void onClick() { // 输入操作
    65. throw new RuntimeException("暂不支持Text的点击事件");
    66. }
    67. @Override
    68. void onRefresh(String content) {
    69. this.content = content;
    70. }
    71. public String getContent() {
    72. Random random = new Random();
    73. String temp = content;
    74. if (temp == null) temp = "";
    75. temp += random.nextInt() + "@";
    76. content = null;
    77. return temp;
    78. }
    79. }
    80. private static class View extends Component {
    81. private String content;
    82. protected View(Mediator mediator, String tag) {
    83. super(mediator, tag);
    84. }
    85. @Override
    86. void onClick() {
    87. mediator.update(content,"text");
    88. }
    89. @Override
    90. void onRefresh(String content) {
    91. this.content = content;
    92. System.out.println("view更新:"+ content);
    93. }
    94. }
    95. private static class Button extends Component {
    96. protected Button(Mediator mediator, String tag) {
    97. super(mediator, tag);
    98. }
    99. @Override
    100. void onClick() {
    101. mediator.update(null,"view");
    102. }
    103. @Override
    104. void onRefresh(String content) {
    105. throw new RuntimeException("暂不支持Button的更新操作");
    106. }
    107. }
    108. }

    1.2 优缺点

    优点:

    1. 简化了对象之间的交互,将原本多对多的交互改成一对多。使得对象之间解耦。
    2. 可以通过中介者类来扩展对象的交互行为,当需要添加或改变交互行为时,只需要添加对应的中介者子类即可,符合开闭原则。
    3. 同事类可以更专注自身业务,而不必关心与其他同事类的交互。

    缺点:

    1. 中介者类包含同事类之间大量的交互细节,使得该类变得非常复杂,不符合单一职责原则。
    2. 中介者类与同事类的耦合度高。

    2 观察者模式

    需求:当目标更新时,能自动通知给订阅者。

    2.1 观察者模式介绍

    当目标对象的状态发生改变时,它的所有观察者都会收到通知。

    图 观察者模式 UML

    1. public class ObserverPattern {
    2. public static void main(String[] args) {
    3. Subject subject = new School();
    4. Observer observer1 = new Teacher();
    5. Observer observer2 = new Student();
    6. subject.attach(observer1);
    7. subject.attach(observer2);
    8. subject.notifyObserverList("快高考啦!");
    9. subject.notifyObserverList("六一放假");
    10. }
    11. private static abstract class Subject {
    12. protected final Set<Observer> observerList = new HashSet<>();
    13. public void attach(Observer observer) {
    14. observerList.add(observer);
    15. }
    16. public void detach(Observer observer) {
    17. observerList.remove(observer);
    18. }
    19. public void notifyObserverList(String content) {
    20. beforeNotify(content);
    21. for (Observer observer : observerList) observer.update(content);
    22. afterNotify(content);
    23. }
    24. public abstract void beforeNotify(String content);
    25. public abstract void afterNotify(String content);
    26. }
    27. private static class School extends Subject {
    28. @Override
    29. public void beforeNotify(String content) {
    30. System.out.println("通知时间:" + new Date());
    31. }
    32. @Override
    33. public void afterNotify(String content) {
    34. System.out.println("通知完成");
    35. }
    36. }
    37. private interface Observer {
    38. void update(String content);
    39. }
    40. private static class Student implements Observer {
    41. @Override
    42. public void update(String content) {
    43. if (content.contains("放假")) System.out.println("学生,耶耶耶!");
    44. else System.out.println("学生,哦哦哦");
    45. }
    46. }
    47. private static class Teacher implements Observer {
    48. @Override
    49. public void update(String content) {
    50. System.out.println("老师,收到:" + content);
    51. }
    52. }
    53. }

    2.2 优缺点

    优点:

    1. 当目标状态更新时,能自动发生通知给订阅者。
    2. 观察者与被观察者耦合度低,符合依赖倒置原则。

    缺点:

    1. 当观察者数量较多时,通知耗时会加长。一个观察者的卡顿会影响整体执行效率

    3 模版方法模式

    需求:对方法的执行顺序有要求,而某些特定方法由子类去实现。例如想写排序算法,算法内部中方法的执行顺序相同,但具体排序算法由不同子类实现。

    3.1 模版方法模式介绍

    定义一个操作中的算法框架,将一些步骤延迟到子类中,子类在不改变算法的结构基础上重定义该算法的某些特定步骤。

    图 模版方法模式 UML

    1. public class TemplateMethodPattern {
    2. public static void main(String[] args) {
    3. Worker programmer = new Programmer();
    4. programmer.work();
    5. }
    6. private static abstract class Worker {
    7. public void work() {
    8. punch("上班");
    9. duty();
    10. punch("下班");
    11. }
    12. protected abstract void duty();
    13. protected void punch(String content) {
    14. System.out.println("打卡:" + content);
    15. }
    16. }
    17. private static class Programmer extends Worker {
    18. @Override
    19. protected void duty() {
    20. System.out.println("写bug AND 解决bug");
    21. }
    22. }
    23. }

    3.2 优缺点

    优点:

    1. 可以控制方法执行顺序,当要增加新的方法实现时,只需要添加特定子类。符合开闭原则及里氏替换原则。

    缺点:

    1. 增加了类的个数。
  • 相关阅读:
    我要给你讲的简单明了,Java就是值传递,不服来辩
    MySQL—优化数据库
    一键自助建站系统源码带安装教程 傻瓜式部署搭建,让您的建站更高效
    ES6及更新版本的新特性
    铸坯火焰自动切割系统的设计状况及存在的问题
    力扣-1984. 学生分数的最小差值
    申请实用新型专利有什么好处?及实用新型专利申请流程
    mysql内置功能(走开发的看)
    1463_英飞凌TC275开发板例程覆盖梳理
    【数据可视化】第四章—— 基于pandas的数据可视化(pandas数据结构)
  • 原文地址:https://blog.csdn.net/qq_25308331/article/details/139335658