`

《设计模式》之十八:访问者模式

阅读更多

Visitor Pattern 访问者模式是的定义如下:

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

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

 

访问者模式中的几个角色:

1,Visitor -- 抽象访问接口

声明访问者可以访问哪些元素,具体到程序中就是visit方法的参数定义哪些对象是可以访问的。

2,ConcreteVisitor -- 具体访问者

3,Element -- 抽象元素

接口或者抽象类,声明接受哪一类访问者访问,程序上通过accept方法参数去定义

4,ConcreteElement -- 具体元素

实现accept方法,通常是vistor.visit(this),基本上就形成了一种模式了。

5,ObjectStructure -- 结构对象

远程产生者,一般容纳多个不同类、不同接口的容器,如List、Set、Map等,在项目中,一般很少抽象出这个角色。

 

通用源码:

public abstract class Element {
    // 定义业务逻辑
    public abstract void doSomething();
    // 允许谁来访问
    public abstract void accept(IVisitor visitor);
}

 

public class ConcreteElement1 extends Element {
    @Override
    public void doSomething() {
        System.out.println("do1...");
    }

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}

 

public class ConcreteElement2 extends Element {
    @Override
    public void doSomething() {
        System.out.println("do2...");
    }

    @Override
    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }
}

 

public interface IVisitor {
    // 可以访问哪些对象
    public void visit(ConcreteElement1 element1);
    public void visit(ConcreteElement2 element2);
}

 

public class Visitor implements IVisitor {
    @Override
    public void visit(ConcreteElement1 element1) {
        element1.doSomething();
    }

    @Override
    public void visit(ConcreteElement2 element2) {
        element2.doSomething();
    }
}

 

public class Client {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                new ConcreteElement1().accept(new Visitor());
            } else {
                new ConcreteElement2().accept(new Visitor());
            }
        }
    }
}

 

访问者模式的优点:

1,符合单一职责原则

具体元素角色Element抽象类的两个子类负责数据的加载,而Visitor类则负责报表的展现,两个具体不同的职责非常明确的分开了,各自演绎变化

2,优先的扩展性

由于职责分开,继续增加数据的操作非常快捷,比如要增加一份给大boss的报表,这份报表格式又有所不同,我们只需要在Visitor中增加一个方法,传递数据后整理打印出来即可,原来的Element不动。

3,灵活性非常高

比如那个Employee的例子,如果要统计所有人的奖金,计算规则是员工工资*0.4,部门经理工资*0.6,总经理的工资*0.8,之前我们怎么做的?那么对所有Employee进行循环,然后用instanceof来判断,我勒个擦,太不优美了,这时候用访问者模式就可以完美解决了,把数据扔给访问者,由访问者来统计计算。

 

访问者模式的缺点:

1,具体的元素Element对访问者公布细节

2,具体元素变更比较困难

3,违背了依赖倒置原则

访问者访问的是具体元素,而不是抽象元素,这破坏了依赖倒置原则,扩展比较困难。

 

访问者模式的使用场景:

1,一个对象结构包含很多类对象,它们有不同的接口,比如上面的Employee的子类有普通员工和经理等。而你想对这些对象实施一些依赖于其具体实现类的操作,也就是说用迭代器模式已经不能胜任了,因为你还得去用instanceof去判断类型,囧。

2,需要对一个对象结构(一般来讲是集合)中的对象进行很多次不同并且不相关的操作,而你想避免让这些操作污染这些类对象。

3,访问者模式还可以充当拦截器Interceptor角色使用。

 

访问者模式的扩展:

统计功能:

统计报表是我们经常需要实现的功能,基本上都是一堆计算公式,然后出一个报表,很多项目采用了数据库的存储过程实现,不过这是不推荐的做法。除非海量数据,一晚上要处理上亿、几十亿条数据,除了存储过程来处理还没有其他办法。

public interface IVistor {
	// 首先定义我可以访问普通员工
	public void visit(CommonEmployee commonEmp);
	// 其次还定义我可以访问部门经理
	public void visit(Manager manager);
	// 统计所有员工的工资总和
	public int getTotalSalary();
}

public class Visitor implements IVisitor {
	// 部门经理的系数是5
	private final int managerRatio = 5;
	// 普通员工的系数是3
	private final int commonRatio = 3;
	// 普通员工的工资总和
	private int commmonTotal = 0;
	// 经理工资总和
	private int managerTotal = 0;
	private void calManager(int salary) {
		managerTotal += salary*managerRatio;
	}
	private void calCommon(int salary) {
		commmonTotal += salary*commonRatio;
	}
	public int getTotalSalary() {
		return managerTotal + commmonTotal;
	}
	public void visit(CommonEmployee commonEmp) {
		System.out.println("哥访问的是普通的员工");
		calCommon(commonEmp.getSalary());
	}
	public void visit(Manager manager) {
		System.out.println("哥访问的是经理");
		calManager(manager.getSalary());
	}
}

public class Client {
	public static void main(String[] args) {
		IVisitor vistor = new Visitor();
		List<Employee> list = null;
		for (Employee emp : list) {
			emp.accept(visitor);
		}
		System.out.println("工资总和:" + vistor.getTotalSalary());
	}
}

 

多个访问者:

上面的其实应该分成两个访问者的,一个是仅仅用来展示数据的report的visitor,而另一个是负责汇总的total的visitor。可以增加两个接口,都继承自IVisitor,但是各自有自己的方法。最后循环中调用

emp.accept(reportVisitor);

emp.accept(totalVisitor); 让所有信息在Visitor实例中积累起来。

然后最后面的时候,就可以直接调用各自的方法了。

 

双分派问题:

public interface Role {
    public void accept(AbsActor actor);
}

 

public class UglyRole implements Role {
    @Override
    public void accept(AbsActor actor) {
        actor.act(this);
    }
}

 

public class BeautyRole implements Role {
    @Override
    public void accept(AbsActor actor) {
        actor.act(this);
    }
}

 

public class Client {
    public static void main(String[] args) {
        // 定义一个演员
        AbsActor actor = new UglyActor();
        // 定义一个角色
        Role role = new BeautyRole();
//        // 开始演戏
//        actor.act(role);
//        // 动态绑定
//        actor.act(new BeautyRole());
        // 开始演戏(访问者模式)
        role.accept(actor);
    }
}

 

本人博客已搬家,新地址为:http://yidao620c.github.io/

分享到:
评论

相关推荐

    设计模式C++学习之访问者模式(Visitor)

    访问者模式(Visitor)是一种行为设计模式,它允许在不修改对象结构的前提下向对象结构中的元素添加新的操作。这种模式将算法与数据结构分离,使得算法可以独立于数据结构进行变化,增强了系统的可扩展性。 在C++中...

    设计模式之访问者模式

    访问者模式是一种软件设计模式,它在对象结构中定义了一个访问者的接口,使得该访问者可以访问该结构中的每一个元素,同时不影响这些元素自身的行为。这种模式的主要目的是将数据操作和业务逻辑分离,使得数据结构...

    设计模式之访问者模式(Visitor Pattern)

    **访问者模式(Visitor Pattern)**是一种行为设计模式,它提供了一种在不修改对象结构的情况下增加新操作的方法。这种模式的主要思想是将数据结构与算法分离,使得算法可以在不改变对象结构的情况下独立变化。 在...

    设计模式 访问者模式

    **访问者模式**是一种行为设计模式,它允许在不修改对象结构的情况下添加新的操作。这种模式主要用于处理具有复杂对象结构的情况,使得我们可以对结构中的每个元素执行特定操作,而无需暴露其内部实现。 访问者模式...

    设计模式-访问者模式(讲解及其实现代码)

    访问者模式是一种行为设计模式,它允许在不修改对象结构的情况下向对象添加新的操作。这种模式的核心思想是将数据结构与算法分离,使得算法可以在不改变对象结构的前提下增加对对象的操作。 在软件开发中,有时我们...

    java设计模式之访问者模式

    访问者模式是一种软件设计模式,它允许在不改变对象结构的情况下,在对象的现有结构上增加新的操作。在Java中,这种模式尤其有用,因为它能够帮助我们保持类的封装性,同时提供了一种灵活的方式来扩展对象的功能。...

    设计模式的访问者模式的例子

    访问者模式是一种软件设计模式,它在对象结构中定义了一个访问者的接口,使得该访问者可以访问该结构中的每一个元素,同时不影响对象结构本身。这种模式的主要目的是将数据操作与数据结构分离,使得数据结构的变化...

    设计模式之访问者模式(Visitor)

    访问者模式是一种行为设计模式,它使你可以在不修改对象结构的情况下,为对象添加新的操作。这种模式的核心在于将数据结构与对这些数据的操作解耦,使得增加新的操作变得容易,同时也允许独立地改变元素类和访问者类...

    设计模式 - 访问者模式

    访问者模式(Visitor Pattern)是一种行为设计模式,它使你能在不修改对象结构的前提下向其添加新的操作。这种模式常用于处理具有相同接口或抽象类的对象结构,使得可以在不改变原有结构的基础上增加功能,实现对...

    第二十三讲:访问者模式

    访问者模式是一种行为设计模式,它允许在不修改对象结构的情况下,为对象增加新的操作。这种模式的核心思想是将数据结构与算法解耦,使得算法可以独立于数据结构进行变化,提高了代码的可扩展性和可维护性。 **访问...

    68丨访问者模式(上):手把手带你还原访问者模式诞生的思维过程1

    【访问者模式】是一种行为设计模式,其主要目的是在不修改已有对象结构的前提下,为对象增加新的操作。这种模式在23种经典设计模式中属于较为复杂的一种,因为它的理解和应用相对困难,可能导致代码可读性和可维护性...

    设计模式之访问者模式Java版本实现

    **访问者模式**是软件设计模式中的一种结构型模式,它允许在不修改对象结构的情况下,在对象上增加新的操作。这种模式将数据结构与数据操作分离,使得代码更易于维护和扩展。 在Java中实现访问者模式,通常包括以下...

    java设计模式-访问者模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段...

    设计模式:可复用面向对象软件的基础(非扫描版+高清)

    设计模式分为三类:创建型模式(如单例模式、工厂方法模式)、结构型模式(如代理模式、装饰器模式)和行为型模式(如观察者模式、策略模式)。每种模式都有其特定的用途和适用场景。 4. **具体设计模式详解** - ...

    23种设计模式详解PDF

    设计模式 的分类 总体来说设计模式分为三大类: 创建型模式(5): ...策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

    Java 23种设计模式27访问者模式.pdf

    ### Java设计模式之访问者模式详解 #### 模式动机 访问者模式主要应用于处理一组对象,这组对象通常被存储在一个聚合结构(如列表、树等)中,并且这组对象具有不同的类型。访问者模式的核心思想在于,可以通过向...

    php设计模式案例详解

    3. **访问者设计模式**:将数据结构和对数据的操作分离,使得我们可以独立地增加新的操作,而不需要修改原有的数据结构代码。 4. **模板设计模式**:定义了算法的骨架,允许子类在不改变算法结构的情况下重定义某些...

    设计模式-访问者模式

    ios 平台实现设计模式-访问者模式,以最简单的代码实现访问者模式讲解,主旨在于了解访问者模式,博客:http://blog.sina.com.cn/s/blog_161d504630102wwxe.html

Global site tag (gtag.js) - Google Analytics