美文网首页
设计模式系列-观察者模式,访问者模式

设计模式系列-观察者模式,访问者模式

作者: ztzt123 | 来源:发表于2018-02-23 17:16 被阅读0次

    观察者模式

    observer.png

    Subject被观察者:能够动态地增加、取消观察者,职责是管理观察者并通知观察者。

    Observer观察者: 接收到消息后,进行相应的操作。

    ConcreteSubject:具体的被观察者

    ConcreteObserver:具体的观察者

        //抽象被观察者
        public abstract class Subject {
             //定义一个观察者数组
             private Vector obsVector = new Vector();
             //增加一个观察者
             public void addObserver(Observer o){
                     this.obsVector.add(o);
             }
             //删除一个观察者
             public void delObserver(Observer o){
                     this.obsVector.remove(o);
             }
             //通知所有观察者
             public void notifyObservers(){
                     for(Observer o:this.obsVector){
                             o.update();
                     }
             }
        }
    
        //具体被观察者
        public class ConcreteSubject extends Subject {
             //具体的业务
             public void doSomething(){
                     //something
                     super.notifyObservers();
             }
        }
    
        //观察者接口
        public interface Observer {
             //更新方法
             public void update();
        }
    
        //具体观察者
        public class ConcreteObserver implements Observer {
             //实现更新方法
             public void update() {
                     System.out.println("接收到信息,并进行处理!");
             }
        }
    
        public class Client {
             public static void main(String[] args) {
                     //创建一个被观察者
                     ConcreteSubject subject = new ConcreteSubject();
                     //定义一个观察者
                     Observer obs= new ConcreteObserver();
                     //观察者观察被观察者
                     subject.addObserver(obs);
                     //观察者开始活动了
                     subject.doSomething();
             }
        }
    

    观察者模式的使用场景:

    建立一套触发机制。

    观察者模式的缺点在:

    观察者模式需要考虑一下开发效率和运行效率问题

    访问者模式

    数据操作与数据结构分离的设计模式。是23中设计模式中比较复杂的一个,使用频率不高但是一旦需要使用,就是迫切的需要。

    定义:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

    visitor.jpg

    角色:

    Visitor——抽象访问者:程序中就是visit方法的参数定义哪些对象是可以被访问的

    ConcreteVisitor——具体访问者:它影响访问者访问到一个类后该怎么干,要做什么事情(CEOVisitor,CTOVisitor)

    Element——抽象元素:声明接受哪一类访问者访问,程序上是通过accept方法中的参数来定义的(Staff)

    ConcreteElement——具体元素:实现accept方法,通常是visitor.visit(this),基本上都形成了一种模式了(Engineer,Manager)

    ObjectStruture——结构对象(可选):元素产生者,一般容纳在多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。(Report)

        //员工基类
        public abstract class Staff {
            public String name;
            public int kpi;
            public Staff(String name){
                this.name = name;
                kpi = new Random().nextInt(10);
            }
    
            public abstract void accept(Visitor visitor);
        }
    
        //产品经理
        public class Manager extends Staff{
            public Manager(String name) {
                super(name);
            }
    
            //一年内的产品数量
            public int getProducts(){
                return 100;
            }
    
            @Override
            public void accept(Visitor visitor) {
                visitor.visit(this);
            }
        }
    
        //工程师
        public class Engineer extends Staff{
            public Engineer(String name) {
                super(name);
            }
    
            //一年的代码行数
            public int getCodeLine(){
                return 10000;
            }
    
            @Override
            public void accept(Visitor visitor) {
                visitor.visit(this);
            }
        }
    
        //访问者接口
        public interface Visitor {
            void visit(Engineer engineer);
            void visit(Manager manager);
        }
    
        public class Report {
            List<Staff> list = new ArrayList<>();
            public Report(){
                list.add(new Manager("zhang3"));
                list.add(new Engineer("wang5"));
                list.add(new Engineer("li4"));
                list.add(new Engineer("liuermazi"));
            }
    
            public void showReport(Visitor visitor){
                for (Staff staff : list){
                    staff.accept(visitor);
                }
            }
        }
    
        public class CEOVisitor implements Visitor{
            @Override
            public void visit(Engineer engineer) {
                System.out.print("kpi: " +engineer.kpi);
            }
    
            @Override
            public void visit(Manager manager) {
                System.out.print("kpi: " + manager.kpi);
            }
        }
    
        public class CTOVisitor implements Visitor {
            @Override
            public void visit(Engineer engineer) {
                System.out.print("code: " + engineer.getCodeLine());
            }
    
            @Override
            public void visit(Manager manager) {
                System.out.print("product: "+ manager.getProducts());
            }
        }
    
        public class Client {
            public static void main(String[] args) {
                Report report = new Report();
                //CEO访问者,给CEO看的报表
                report.showReport(new CEOVisitor());
                //CTO访问者,给CTO看的报表
                report.showReport(new CTOVisitor());
            }
        }
    

    思考:

    抽象Staff中使用了Visitor,Visitor依赖于Engineer和Manager(具体的Staff),这样间接导致依赖于具体的Staff,这样设计好不好?

    如果这样写呢?

        public abstract class Staff {
            public String name;
            public int kpi;
            public Staff(String name){
                this.name = name;
                kpi = new Random().nextInt(10);
            }
    
            public void accept(Visitor visitor){
                visitor.visit(this)
            }
        }
    
        //访问者接口
        public interface Visitor {
            void visit(Staff staff);
        }
    
        public class CEOVisitor implements Visitor{
            @Override
            public void visit(Staff staff) {
                if(staff instanceof Manager){
                     Manager manager = (Manager)staff;
                     System.out.print("产品经理kpi: " +manager.kpi);
                }else if(staff instanceof Engineer){
                     Engineer engineer = (Engineer)staff;
                     System.out.print("工程师kpi: " +engineer.kpi);
                }
            }
        }
    

    这样写就不依赖于具体的元素了,也减少了每次调用visit方法。但是增加的是if-else的嵌套以及类型的强制转换,当类型较多时也会变得比较难以维护。各有利弊吧。

    相关文章

      网友评论

          本文标题:设计模式系列-观察者模式,访问者模式

          本文链接:https://www.haomeiwen.com/subject/cuixxftx.html