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

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

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 优缺点

优点:

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

缺点:

  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 优缺点

优点:

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

缺点:

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

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 优缺点

优点:

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

缺点:

  1. 增加了类的个数。
相关推荐
普通程序员A4 小时前
代码技巧专题 -- 使用策略模式编写HandleService
设计模式·面试·策略模式·代码优化·handle
吕彬-前端6 小时前
es6之Proxy实现观察者模式
前端·观察者模式·es6
yunhuibin8 小时前
DP学习——观察者模式
设计模式
二进制人工智能10 小时前
【C++设计模式】(一)面向对象编程的八大原则
c++·设计模式
肖哥弹架构1 天前
适配器模式(Adapter Pattern):第三方支付集成实战案例分析
java·后端·设计模式
肖哥弹架构1 天前
原型模式(Prototype Pattern): 云服务环境配置实战案例分析
java·后端·设计模式
肖哥弹架构1 天前
建造者模式(Builder Pattern): 在线订单系统实战案例分析
java·后端·设计模式
被拯救的威尼斯1 天前
设计模式-结构型-08-组合模式
设计模式·组合模式
且随疾风前行.1 天前
技术成神之路:设计模式(三)原型模式
设计模式·原型模式
吃青椒的小新1 天前
独一无二的设计模式——单例模式(Java实现)
java·后端·单例模式·设计模式