访问者模式:设计模式系列(二十一)

  访问者模式(Visitor Pattern):是一种让类实例对象在不改变自身的前提下能让访问者扩展定义访问自身的方法的设计模式,归类为行为型模式。

  这一模式的解读分为以下几个方面:

  • 被访问类自身不作出改变。
  • 访问者访问方式不定。
  • 访问者可自定义访问方式。

  使用访问者模式的思考过程如下:

  1. 一些类的职责已经明确被指定。
  2. 需要这些类实现一些与职责不太相关的操作。
  3. 把这些操作封装到访问者类中,需要的时候通过访问者模式调用。

  明确一下结构,访问者模式结构包含被访问的实现类、被访问的实现类抽象出来的协议或接口、管理被访问类实例对象的容器类、访问者类、访问者抽象出来的接口或协议。

访问者模式示例代码如下(Swift语言):

protocol ObjectBluePrint{
    
    var id:Int{get set};
    func show();
    func tell();
    func accept(visitor:VisitorBluePrint);
}

class Object1:ObjectBluePrint{
    
    var id:Int;
    
    init(id:Int){
        self.id = id;
    }
    
    func show(){
        print("I am from Object 1");
    }
    
    func tell() {
        print("I am One");
    }
    
    func accept(visitor: VisitorBluePrint) {
        visitor.visitObject(self);
    }
}

class Object2:ObjectBluePrint{
    
    var id:Int;
    
    init(id:Int){
        self.id = id;
    }
    
    func show(){
        print("I am from Object 2");
    }
    
    func tell() {
        print("I am Two");
    }
    
    func accept(visitor: VisitorBluePrint) {
        visitor.visitObject(self);
    }
}

protocol VisitorBluePrint{
    
    func visitObject(object:ObjectBluePrint);
}

class Visitor1:VisitorBluePrint{
    
    func visitObject(object: ObjectBluePrint) {
        object.show();
        object.tell();
    }
}

class Visitor2:VisitorBluePrint{
    
    func visitObject(object: ObjectBluePrint) {
        object.tell();
        object.show();
    }
}

class Manager{
    
    var objects:[ObjectBluePrint]?;
    
    func register(object:ObjectBluePrint){
        if(self.objects == nil){
            self.objects = [ObjectBluePrint]();
        }
        self.objects!.append(object);
    }
    
    func unregister(object:ObjectBluePrint){
        for(var i = 0;i < self.objects?.count;i++){
            if(self.objects![i].id == object.id){
                self.objects!.removeAtIndex(i);
            }
        }
    }
}

var obj1:ObjectBluePrint = Object1(id: 0);
var obj2:ObjectBluePrint = Object2(id: 1);
var manager = Manager();
manager.register(obj1);
manager.register(obj2);

manager.objects![0].accept(Visitor1());
manager.objects![1].accept(Visitor2());

  代码分析:Object1Object2是遵循类ObjectBluePrint协议的被访问类,内有接受遵循VisitorBluePrint协议的实现类的方法accept,这方法中是通过参数访问者对象调用visitObject方法从而调用被访问者的showtell方法,而Manager类实例化对象则充当被访问者的容器。这一段代码完成了被访问者在不改变的情况下让访问者扩展定义访问自身的方法,最后的输出结果如下:

I am from Object 1
I am One
I am Two
I am from Object 2

  总结:访问者模式是一个不常用的设计模式,之所以这么说,除了因为适用的场景很少,还因为很多时候不要为了使用而使用。另外上面代码中还有很多可以扩展的地方(比如VisitObject方法就实现得很简单),思考设计模式,一定不能想着现象并且套进去,其本质才是重点。


lZackx © 2022. All rights reserved.

Powered by Hydejack v9.1.6