实例讲解iOS应用的设计模式开发中的Visitor访问者模式

所属分类: 软件编程 / IOS 阅读数: 958
收藏 0 赞 0 分享

为了方便向大家展示,先给出简短的定义:

访问者模式(Visitor),表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

紧接着,给出其类结构图。

201632293447218.jpg (500×385)
访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作结合可以相对自由地演化。

访问者模式的目的是要把处理从数据结构分离出来。很多系统可以按照算法和数据结构分开,如果这样的系统有比较稳定的数据结构,又有易于变化的算法的话,使用访问者模式就是比较合适的,因为访问者模式使得算法操作的增加变得容易。

访问者模式的优点就是增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。

那其实,访问者模式的缺点也就是使增加新的数据结构变得苦难了。所以,GoF四人中的一个作者增经说过,‘大多时候你并不需要访问者模式,但当一旦你需要访问者模式的时候,那就是真的需要它了'。

那么下面还是老惯例,给大家展示一下简单的实现。
一个简单的Car模型,含有1台Engine、4个Wheel,使用访问者模式添加对Car的升级与维修操作。

定义Engine类:

复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "NimoComponentVisitor.h"
 
@interface NimoEngine : NSObject
 
@property (nonatomic, copy) NSString *modelName;
- (id)initWithModelName:(NSString *)modelName;
 
@end

复制代码 代码如下:

#import "NimoEngine.h"
 
@implementation NimoEngine
 
- (id)initWithModelName:(NSString *)modelName
{
    self = [super init];
    if (self) {
        _modelName = [modelName copy];
    }
    return self;
}
 
- (id) init
{
    return [self initWithModelName:@"Slant 6"];
}
 
- (NSString *)description
{
    return [NSString stringWithFormat:@"Engine: %@", _modelName];
}
 
@end

定义Wheel类:
复制代码 代码如下:

#import <Foundation/Foundation.h>
 
@interface NimoWheel : NSObject
 
@property (nonatomic, assign) float diameter; //车轮直径
 
@end

复制代码 代码如下:

#import "NimoWheel.h"
 
@implementation NimoWheel
 
- (id)init
{
    self = [super init];
    if (self) {
        _diameter = 400.0f;
    }
    return self;
}
 
-(NSString *)description
{
    return [NSString stringWithFormat:@"Wheel: %f mm", _diameter];
}
 
@end

定义Car类:
复制代码 代码如下:

#import <Foundation/Foundation.h>
 
@class NimoEngine, NimoWheel;
 
@interface NimoCar : NSObject
 
@property (nonatomic) NimoEngine *engine;
@property (nonatomic, readonly) NSArray *arrayOfWheels;
 
- (void)addWheel:(NimoWheel *)wheel atIndex:(NSUInteger) index;
 
@end

复制代码 代码如下:

@interface NimoCar()
 
@property (nonatomic, readwrite) NSMutableArray *mutableArrayOfWheels;
 
@end

复制代码 代码如下:

@implementation NimoCar
 
- (id)init
{
    if (self = [super init]) {
        _mutableArrayOfWheels = [[NSMutableArray alloc] initWithCapacity:4];
    }
    
    return self;
}
 
- (void)addWheel:(NimoWheel *)wheel atIndex:(NSUInteger) index
{
    [_mutableArrayOfWheels insertObject:wheel atIndex:index];
}
 
- (NSArray *)arrayOfWheels
{
    return [_mutableArrayOfWheels copy];
}
 
- (NSString *)description
{
    return [NSString stringWithFormat:@"My car: %@", [NSDictionary dictionaryWithObjects:@[_engine, self.arrayOfWheels] forKeys:@[@"Engine", @"Wheels"]]];
}
 
@end

我们的汽车结构很简单,只包含1个引擎,4个车轮,并且各个类也没有复杂的实现,仅仅覆写了description,让其输出简要的信息。

好,实例化一辆Car, 看看效果:

复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "NimoCar.h"
#import "NimoEngine.h"
#import "NimoWheel.h"
 
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        NimoCar *car = [[NimoCar alloc] init];
        NimoEngine *engine = [[NimoEngine alloc] initWithBrandName:@"V8"];
        NimoWheel *wheelA = [[NimoWheel alloc] init];
        NimoWheel *wheelB = [[NimoWheel alloc] init];
        NimoWheel *wheelC = [[NimoWheel alloc] init];
        NimoWheel *wheelD = [[NimoWheel alloc] init];
        
        car.engine = engine;
        [car addWheel:wheelA atIndex:0];
        [car addWheel:wheelB atIndex:1];
        [car addWheel:wheelC atIndex:2];
        [car addWheel:wheelD atIndex:3];
        
        NSLog(@"%@", car);
        
    }
    return 0;
}

201632293536226.png (768×152)

控制台跟意料中一样输出了Car的信息。至此,准备工作做好了。

访问者模式:表示一个作用于某对象结构中的各元素的操作。它让我们可以在不改变各元素的类的前提下定义作用于这些元素的新操作。---《设计模式》(Addison-Wesley, 1994)

这段话比较拗口,不太好理解。拿刚刚完成的Car类来举例,NimoCar类就是对象结构,其中包含的元素为:NimoEngine类和NimoWheel类。如果现在需要对Car进行全面升级(新操作),通常的做法是NimoEngine与NimoWheel都向外提供“升级”的接口。如果还需要对Car进行维修呢?那又得向外提供“维修”的接口。随着类似的需求越多,NimoEngine与NimoWheel向外提供的接口就越多,类也变得越复杂。有没有简单的方法呢?有!把这些琐事都交给访问者来做吧,NimoEngine与NimoWheel只要同意被访问就成。

定义访问者协议:

复制代码 代码如下:

@class NimoEngine, NimoWheel;
 
@protocol NimoComponentVisitor <NSObject>
 
- (void) visitEngine:(NimoEngine *) engine;
- (void) visitWheel:(NimoWheel *) wheel;
 
@end

修改我们的类,使其能够接受访问

添加访问支持的Engine类:

复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "NimoComponentVisitor.h"
 
@interface NimoEngine : NSObject
 
@property (nonatomic, copy) NSString *modelName;
 
- (id)initWithModelName:(NSString *)modelName;
 
- (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor;
 
@end

复制代码 代码如下:

#import "NimoEngine.h"
 
@implementation NimoEngine
 
- (id)initWithModelName:(NSString *)modelName
{
    self = [super init];
    if (self) {
        _modelName = [modelName copy];
    }
    return self;
}
 
- (id) init
{
    return [self initWithModelName:@"Slant 6"];
}
 
- (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor
{
    [visitor visitEngine:self];
}
 
- (NSString *)description
{
    return [NSString stringWithFormat:@"Engine: %@", _modelName];
}
 
@end

添加访问支持的Wheel类:
复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "NimoComponentVisitor.h"
 
@interface NimoWheel : NSObject
 
@property (nonatomic, assign) float diameter; //直径
 
- (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor;
 
@end

复制代码 代码如下:

#import "NimoWheel.h"
 
@implementation NimoWheel
 
- (id)init
{
    self = [super init];
    if (self) {
        _diameter = 400.0f;
    }
    return self;
}
 
- (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor
{
    [visitor visitWheel:self];
}
 
-(NSString *)description
{
    return [NSString stringWithFormat:@"Wheel: %f mm", _diameter];
}
 
@end

添加访问支持的Car类
复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "NimoComponentVisitor.h"
 
@class NimoEngine, NimoWheel;
 
@interface NimoCar : NSObject
 
@property (nonatomic) NimoEngine *engine;
@property (nonatomic, readonly) NSArray *arrayOfWheels;
 
- (void)addWheel:(NimoWheel *)wheel atIndex:(NSUInteger) index;
 
- (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor;
@end

复制代码 代码如下:

#import "NimoCar.h"
#import "NimoEngine.h"
#import "NimoWheel.h"
 
@interface NimoCar()
 
@property (nonatomic, readwrite) NSMutableArray *mutableArrayOfWheels;
 
@end

复制代码 代码如下:

@implementation NimoCar
 
- (id)init
{
    if (self = [super init]) {
        _mutableArrayOfWheels = [[NSMutableArray alloc] initWithCapacity:4];
    }
    
    return self;
}
 
- (void)addWheel:(NimoWheel *)wheel atIndex:(NSUInteger) index
{
    [_mutableArrayOfWheels insertObject:wheel atIndex:index];
}
 
- (NSArray *)arrayOfWheels
{
    return [_mutableArrayOfWheels copy];
}
 
- (void)acceptComponentVisitor:(id<NimoComponentVisitor>) visitor
{
    [_engine acceptComponentVisitor:visitor];
    for (NimoWheel *wheel in self.arrayOfWheels) {
        [wheel acceptComponentVisitor:visitor];
    }
}
 
- (NSString *)description
{
    return [NSString stringWithFormat:@"My car: %@", [NSDictionary dictionaryWithObjects:@[_engine, self.arrayOfWheels] forKeys:@[@"Engine", @"Wheels"]]];
}
 
@end

我们在类中添加了-(void)acceptComponentVisitor:(id<NimoComponentVisitor>)visitor接口,同意实现了访问者协议的visitor访问。(我家大门常打开,啦啦啦啦啦)

让我们来看下第一位访问者是谁?刚刚上面我们有提到一个需求,想对汽车各组件进行全面升级。那么就让这位专业的访问者来做吧!

定义具体访问者:此访问者具备升级汽车各组件的能力

复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "NimoComponentVisitor.h"
 
@interface NimoComponentUpgrade : NSObject <NimoComponentVisitor>
 
- (void) visitEngine:(NimoEngine *) engine;
- (void) visitWheel:(NimoWheel *) wheel;
 
@end

复制代码 代码如下:

#import "NimoComponentUpgrade.h"
 
@implementation NimoComponentUpgrade
 
- (void) visitEngine:(NimoEngine *) engine
{
    NSLog(@"我是升级人员,正在对引擎<%@>进行升级", engine);
}
 
- (void) visitWheel:(NimoWheel *) wheel
{
    NSLog(@"我是升级人员,正在对车轮<%@>进行升级", wheel);
}
 
@end

让我们来看看这位访问者的工作能力如何
复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "NimoCar.h"
#import "NimoEngine.h"
#import "NimoWheel.h"
#import "NimoComponentMaintenance.h"
#import "NimoComponentUpgrade.h"
 
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        NimoCar *car = [[NimoCar alloc] init];
        NimoEngine *engine = [[NimoEngine alloc] initWithModelName:@"V8"];
        NimoWheel *wheelA = [[NimoWheel alloc] init];
        NimoWheel *wheelB = [[NimoWheel alloc] init];
        NimoWheel *wheelC = [[NimoWheel alloc] init];
        NimoWheel *wheelD = [[NimoWheel alloc] init];
        
        car.engine = engine;
        [car addWheel:wheelA atIndex:0];
        [car addWheel:wheelB atIndex:1];
        [car addWheel:wheelC atIndex:2];
        [car addWheel:wheelD atIndex:3];
        
        NSLog(@"%@", car);
        
        //对组建进行“升级”
        NimoComponentUpgrade *upgradeVisitor = [[NimoComponentUpgrade alloc] init];
        [car acceptComponentVisitor:upgradeVisitor];
    }
    return 0;
}

201632293606776.jpg (768×243)

看来这位访问者的工作很出色。

如果我们还需要对汽车各组件进行维修呢?那就定义一个专职维修的访问者

复制代码 代码如下:

#import <Foundation/Foundation.h>
#import "NimoComponentVisitor.h"
 
@interface NimoComponentMaintenance : NSObject <NimoComponentVisitor>
 
- (void) visitEngine:(NimoEngine *) engine;
- (void) visitWheel:(NimoWheel *) wheel;
 
@end

复制代码 代码如下:

#import "NimoComponentMaintenance.h"
 
@implementation NimoComponentMaintenance
 
- (void) visitEngine:(NimoEngine *) engine
{
    NSLog(@"我是维修人员,正在对引擎<%@>进行维修", engine);
}
 
- (void) visitWheel:(NimoWheel *) wheel
{
    NSLog(@"我是维修人员,正在对车轮<%@>进行维修", wheel);
}
 
@end

复制代码 代码如下:

//main.m
        ...
        //对组建进行“维修”
        NimoComponentMaintenance *maintenanceVisitor = [[NimoComponentMaintenance alloc] init];
        [car acceptComponentVisitor:maintenanceVisitor];
        ...
       

使用访问者模式后,添加操作,只需实现具体的访问者,不会对类的结构造成破坏。

更多精彩内容其他人还在看

iOS开发笔记--详解UILabel的相关属性设置

这篇文章主要介绍了iOS开发笔记--详解UILabel的相关属性设置,对初学者具有一定的参考价值,有需要的可以了解一下。
收藏 0 赞 0 分享

iOS中获取系统相册中的图片实例

这篇文章主要介绍了iOS中获取系统相册中的图片实例,具有一定的参考价值没有需要的朋友可以了解一下。
收藏 0 赞 0 分享

iOS 检测网络状态的两种方法

一般有Reachability和AFNetworking监测两种方式,都是第三方的框架,下文逐一详细给大家讲解,感兴趣的朋友一起看看吧
收藏 0 赞 0 分享

IOS 性能优化中离屏渲染

本文主要介绍了IOS 性能优化中离屏渲染的资料,提供了几种方法讲解了优化,有需要的小伙伴可以参考下
收藏 0 赞 0 分享

iOS获取当前设备型号等信息(全)包含iPhone7和iPhone7P

这篇文章主要介绍了iOS获取当前设备型号设备信息的总结包含iPhone7和iPhone7P,包括ios7之前之后的获取方式,本文接的非常详细,具有参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

iOS实现爆炸的粒子效果示例代码

之前在网上看到了一个Android实现的爆炸效果,感觉非常不错,所以自己尝试用iOS来实现下效果,现在将实现的过程、原理以及遇到的问题分享给大家,有需要的朋友们可以参考借鉴,下面来一起看看吧。
收藏 0 赞 0 分享

iOS毕业设计之天气预报App

这篇文章主要为大家详细介绍了iOS毕业设计之天气预报App,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

iOS轻点、触摸和手势代码开发

这篇文章主要为大家详细介绍了iOS轻点、触摸和手势代码开发,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

iOS 实现多代理的方法及实例代码

这篇文章主要介绍了iOS 实现多代理的方法及实例代码的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

iOS文字渐变色效果的实现方法

在大家日常开发iOS的过程中,可能会遇到要实现文字渐变色的效果,这篇文章文章通过示例代码和详细的步骤介绍了如何利用iOS实现文字渐变色的效果,实现后的很不错,感兴趣的朋友们下面来一起看看吧。
收藏 0 赞 0 分享
查看更多