服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - 实例讲解iOS应用的设计模式开发中的Visitor访问者模式

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

2021-01-11 16:46TonyGo IOS

这篇文章主要介绍了iOS应用的设计模式开发中的Visitor访问者模式的实例,示例代码为传统的Objective-C,需要的朋友可以参考下

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

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

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

实例讲解iOS应用的设计模式开发中的Visitor访问者模式
访问者模式适用于数据结构相对稳定的系统,它把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作结合可以相对自由地演化。

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

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

那其实,访问者模式的缺点也就是使增加新的数据结构变得苦难了。所以,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;
}

 

 

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

控制台跟意料中一样输出了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;
}

 

 

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

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

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

复制代码 代码如下:

#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];
        ...
       


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

延伸 · 阅读

精彩推荐
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01