这篇文章是我对大话设计模式-装饰模式中所举三个例子的OC代码实现,所以配合大话设计模式这本书来阅读更容易理解装饰模式的概念。OK,按照本书的思路,让我们首先来看一下‘小菜扮靓第一版’的代码实现:
Person.h
-(void)wearTShirts;
-(void)wearBigTrouser;//垮裤
-(void)wearSneakers;//破球鞋
-(void)wearSuit;//西装
-(void)wearTie;//领带
-(void)wearLeatherShoes;
-(void)showName:(NSString *)name;
Person.m
-(void)wearTShirts;
{
NSLog(@"大T恤");
}
-(void)wearBigTrouser;
{
NSLog(@"垮裤");
}
-(void)wearSneakers;
{
NSLog(@"破球鞋");
}
-(void)wearSuit;
{
NSLog(@"西装");
}
-(void)wearTie;
{
NSLog(@"领带");
}
-(void)wearLeatherShoes;
{
NSLog(@"皮鞋");
}
-(void)showName:(NSString *)name;
{
NSLog(@"装扮的%@",name);
}
main.m
Person *per=[Person new];
[per wearTShirts];
[per wearBigTrouser];
[per wearLeatherShoes];
[per showName:@"张三"];
打印:
2015-05-21 20:05:02.537 第一次[12080:1856669] 大T恤
2015-05-21 20:05:02.539 第一次[12080:1856669] 垮裤
2015-05-21 20:05:02.539 第一次[12080:1856669] 皮鞋
2015-05-21 20:05:02.539 第一次[12080:1856669] 装扮的张三
分析:不易扩展,代码繁琐;
'小菜扮靓第二版'
/*Person是一个类,Finery是TShirts、BigTrouser、Sneakers的父类,继承Finery的show装扮方法*/
Person.h
-(void)showName:(NSString *)name;
Person.m
-(void)showName:(NSString *)name
{
NSLog(@"装扮的%@",name);
}
Finery.h
-(void)show;
Finery.m
-(void)show
{
NSLog(@"穿衣服");
}
TShirts.m
-(void)show
{
NSLog(@"大T恤");
}
BigTrouser.m
-(void)show
{
NSLog(@"垮裤");
}
Sneakers.m
-(void)show
{
NSLog(@"破球鞋");
}
main.m//导入头文件
Person *per=[Person new];
Finery *fin=[Finery new];
TShirts *tshirts=[TShirts new];
BigTrouser *bigT=[BigTrouser new];
Sneakers *sn=[Sneakers new];
[per showName:@"张三"];
[fin show];
[tshirts show];
[bigT show];
[sn show];
打印:
2015-05-21 20:14:53.593 第二次[12117:1862009] 装扮的张三
2015-05-21 20:14:53.637 第二次[12117:1862009] 穿衣服
2015-05-21 20:14:53.638 第二次[12117:1862009] 大T恤
2015-05-21 20:14:53.638 第二次[12117:1862009] 垮裤
2015-05-21 20:14:53.638 第二次[12117:1862009] 破球鞋
分析:不能把所需的功能按照正确的顺序串联起来进行控制
‘小菜扮靓第三版’
/*Person是父类,Decorator是子类,TShirts、BigTrouser、Leathershoes继承自Decorator*/
Person.h
@property(strong ,nonatomic)NSString *name;
-(NSString *)show;
Person.m
-(NSString *)show
{
return [NSString stringWithFormat:@"装扮的%@",_name];
}
/*Decorator类是装饰模式的精髓,通过赋值运算符'='将per2赋给per1,使per1可以调用per2,让程序更加灵活了*/
Decorator.h
//声明一个和父类同类型的属性per1
@property(strong ,nonatomic)Person *per1;
//声明和父类同类型的输入成员变量per2
-(void)setPerson:(Person *)per2;
Decorator.m
-(void)setPerson:(Person *)per2
{
_per1=per2;
}
-(NSString *)show
{
return _per1.show;
}
TShirts.m
-(NSString *)show
{
return [NSString stringWithFormat:@"T恤 %@ ",[super show]];
}
BigTrouser.m
-(NSString *)show
{
return [NSString stringWithFormat:@" 垮裤 %@ ",[super show]];
}
LeatherShoes.m
-(NSString *)show
{
return [NSString stringWithFormat:@"皮鞋 %@",[super show]];
}
main.m//导入头文件
Person *per=[Person new];
per.name=@"张三";
NSLog(@"%@",per.show);
TShirts *tshirt=[TShirts new];
[tshirt setPerson:per];
NSLog(@"%@",tshirt.show);
BigTrouser *big=[BigTrouser new];
[big setPerson:tshirt];
NSLog(@"%@",big.show);
LeatherShoes *lea=[LeatherShoes new];
[lea setPerson:big];
NSLog(@"%@",lea.show);
打印:
2015-05-21 20:29:48.114 第三次[12151:1868387] 装扮的张三
2015-05-21 20:29:48.115 第三次[12151:1868387] T恤 装扮的张三
2015-05-21 20:29:48.115 第三次[12151:1868387] 垮裤 T恤 装扮的张三
2015-05-21 20:29:48.115 第三次[12151:1868387] 皮鞋 垮裤 T恤 装扮的张三
书上的例子到此为止,但是即便是第三次装饰的代码也由于实际情况省略了Component接口类,所以补充一个能基本展示装饰模式各部分功能的例子:
对某个手机的内容功能扩展 首先,我们需要一个手机的接口或者抽象类,我这里就用抽象类来实现,代码如下:
@interface Phone : NSObject
-(NSString *)callNumber;
-(NSString *)sendMassage;
@end
@implementation Phone
-(NSString *)callNumber
{
return @"Phone call GF";
}
-(NSString *)sendMassage
{
return @"Phone send a massage to GF";
}
@end
Phone也就是结构图中的Component,然后,我再来实现iphone手机类,这类要继承Phone,也就是图中ConcreteComponent类要继承Component,实现代码如下:
@interface Iphone : Phone
@end
@implementation Iphone
-(NSString *)callNumber
{
return @"Using iphone6plus call GF";
}
-(NSString *)sendMassage
{
return @"Using iphone6plus send a message to GF";
}
@end
接下来我需要一个Decorator接口或者抽象类,实现代码如下:
@interface Decroato : Phone
@property(copy,nonatomic)Phone *phone;
-(void)setPhone:(Phone *)phones;
@end
@implementation Decroato
@synthesize phone;
-(void)setPhone:(Phone *)phones
{
phone=phones;
}
-(NSString *)callNumber
{
return phone.callNumber;
}
-(NSString *)sendMassage
{
return phone.sendMassage;
}
@end
正如结构图中,这个Decorator即继承了Phone,又包含了一个私有的Phone的对象。这样做的意义是:Decorator类又使用了另外一个Phone类。我们可以使用一个或多个Decorator对象来“装饰”一个Phone对象,且装饰后的对象仍然是一个Phone对象。在下来,我要实现内容(Content)的功能扩展,它们要继承自Decorator,代码如下:
@interface Content : Decroato
@end
@implementation Content
-(NSString *)callNumber
{
return [NSString stringWithFormat:@"%@ say:I LOVE YOU",[super callNumber]];
}
-(NSString *)sendMassage
{
return [NSString stringWithFormat:@"%@ say:I LOVE YOU",[super sendMassage]];
}
@end
最后,用客户端程序验证一下:
Phone *phone=[Iphone new];
NSLog(@"%@",phone.callNumber);
NSLog(@"%@",phone.sendMassage);
Content *content=[Content new];
[content setPhone:phone];
NSLog(@"%@",content.callNumber);
NSLog(@"%@",content.sendMassage);
打印:
2015-05-21 21:03:06.375 Decrotor[12220:1880459] Using iphone6plus call GF
2015-05-21 21:03:06.376 Decrotor[12220:1880459] Using iphone6plus send a message to GF
2015-05-21 21:03:06.376 Decrotor[12220:1880459] Using iphone6plus call GF say:I LOVE YOU
2015-05-21 21:03:06.376 Decrotor[12220:1880459] Using iphone6plus send a message to GF say:I LOVE YOU
OVER...
Person.h
-(void)wearTShirts;
-(void)wearBigTrouser;//垮裤
-(void)wearSneakers;//破球鞋
-(void)wearSuit;//西装
-(void)wearTie;//领带
-(void)wearLeatherShoes;
-(void)showName:(NSString *)name;
Person.m
-(void)wearTShirts;
{
NSLog(@"大T恤");
}
-(void)wearBigTrouser;
{
NSLog(@"垮裤");
}
-(void)wearSneakers;
{
NSLog(@"破球鞋");
}
-(void)wearSuit;
{
NSLog(@"西装");
}
-(void)wearTie;
{
NSLog(@"领带");
}
-(void)wearLeatherShoes;
{
NSLog(@"皮鞋");
}
-(void)showName:(NSString *)name;
{
NSLog(@"装扮的%@",name);
}
main.m
Person *per=[Person new];
[per wearTShirts];
[per wearBigTrouser];
[per wearLeatherShoes];
[per showName:@"张三"];
打印:
2015-05-21 20:05:02.537 第一次[12080:1856669] 大T恤
2015-05-21 20:05:02.539 第一次[12080:1856669] 垮裤
2015-05-21 20:05:02.539 第一次[12080:1856669] 皮鞋
2015-05-21 20:05:02.539 第一次[12080:1856669] 装扮的张三
分析:不易扩展,代码繁琐;
'小菜扮靓第二版'
/*Person是一个类,Finery是TShirts、BigTrouser、Sneakers的父类,继承Finery的show装扮方法*/
Person.h
-(void)showName:(NSString *)name;
Person.m
-(void)showName:(NSString *)name
{
NSLog(@"装扮的%@",name);
}
Finery.h
-(void)show;
Finery.m
-(void)show
{
NSLog(@"穿衣服");
}
TShirts.m
-(void)show
{
NSLog(@"大T恤");
}
BigTrouser.m
-(void)show
{
NSLog(@"垮裤");
}
Sneakers.m
-(void)show
{
NSLog(@"破球鞋");
}
main.m//导入头文件
Person *per=[Person new];
Finery *fin=[Finery new];
TShirts *tshirts=[TShirts new];
BigTrouser *bigT=[BigTrouser new];
Sneakers *sn=[Sneakers new];
[per showName:@"张三"];
[fin show];
[tshirts show];
[bigT show];
[sn show];
打印:
2015-05-21 20:14:53.593 第二次[12117:1862009] 装扮的张三
2015-05-21 20:14:53.637 第二次[12117:1862009] 穿衣服
2015-05-21 20:14:53.638 第二次[12117:1862009] 大T恤
2015-05-21 20:14:53.638 第二次[12117:1862009] 垮裤
2015-05-21 20:14:53.638 第二次[12117:1862009] 破球鞋
分析:不能把所需的功能按照正确的顺序串联起来进行控制
‘小菜扮靓第三版’
/*Person是父类,Decorator是子类,TShirts、BigTrouser、Leathershoes继承自Decorator*/
Person.h
@property(strong ,nonatomic)NSString *name;
-(NSString *)show;
Person.m
-(NSString *)show
{
return [NSString stringWithFormat:@"装扮的%@",_name];
}
/*Decorator类是装饰模式的精髓,通过赋值运算符'='将per2赋给per1,使per1可以调用per2,让程序更加灵活了*/
Decorator.h
//声明一个和父类同类型的属性per1
@property(strong ,nonatomic)Person *per1;
//声明和父类同类型的输入成员变量per2
-(void)setPerson:(Person *)per2;
Decorator.m
-(void)setPerson:(Person *)per2
{
_per1=per2;
}
-(NSString *)show
{
return _per1.show;
}
TShirts.m
-(NSString *)show
{
return [NSString stringWithFormat:@"T恤 %@ ",[super show]];
}
BigTrouser.m
-(NSString *)show
{
return [NSString stringWithFormat:@" 垮裤 %@ ",[super show]];
}
LeatherShoes.m
-(NSString *)show
{
return [NSString stringWithFormat:@"皮鞋 %@",[super show]];
}
main.m//导入头文件
Person *per=[Person new];
per.name=@"张三";
NSLog(@"%@",per.show);
TShirts *tshirt=[TShirts new];
[tshirt setPerson:per];
NSLog(@"%@",tshirt.show);
BigTrouser *big=[BigTrouser new];
[big setPerson:tshirt];
NSLog(@"%@",big.show);
LeatherShoes *lea=[LeatherShoes new];
[lea setPerson:big];
NSLog(@"%@",lea.show);
打印:
2015-05-21 20:29:48.114 第三次[12151:1868387] 装扮的张三
2015-05-21 20:29:48.115 第三次[12151:1868387] T恤 装扮的张三
2015-05-21 20:29:48.115 第三次[12151:1868387] 垮裤 T恤 装扮的张三
2015-05-21 20:29:48.115 第三次[12151:1868387] 皮鞋 垮裤 T恤 装扮的张三
书上的例子到此为止,但是即便是第三次装饰的代码也由于实际情况省略了Component接口类,所以补充一个能基本展示装饰模式各部分功能的例子:
对某个手机的内容功能扩展 首先,我们需要一个手机的接口或者抽象类,我这里就用抽象类来实现,代码如下:
@interface Phone : NSObject
-(NSString *)callNumber;
-(NSString *)sendMassage;
@end
@implementation Phone
-(NSString *)callNumber
{
return @"Phone call GF";
}
-(NSString *)sendMassage
{
return @"Phone send a massage to GF";
}
@end
Phone也就是结构图中的Component,然后,我再来实现iphone手机类,这类要继承Phone,也就是图中ConcreteComponent类要继承Component,实现代码如下:
@interface Iphone : Phone
@end
@implementation Iphone
-(NSString *)callNumber
{
return @"Using iphone6plus call GF";
}
-(NSString *)sendMassage
{
return @"Using iphone6plus send a message to GF";
}
@end
接下来我需要一个Decorator接口或者抽象类,实现代码如下:
@interface Decroato : Phone
@property(copy,nonatomic)Phone *phone;
-(void)setPhone:(Phone *)phones;
@end
@implementation Decroato
@synthesize phone;
-(void)setPhone:(Phone *)phones
{
phone=phones;
}
-(NSString *)callNumber
{
return phone.callNumber;
}
-(NSString *)sendMassage
{
return phone.sendMassage;
}
@end
正如结构图中,这个Decorator即继承了Phone,又包含了一个私有的Phone的对象。这样做的意义是:Decorator类又使用了另外一个Phone类。我们可以使用一个或多个Decorator对象来“装饰”一个Phone对象,且装饰后的对象仍然是一个Phone对象。在下来,我要实现内容(Content)的功能扩展,它们要继承自Decorator,代码如下:
@interface Content : Decroato
@end
@implementation Content
-(NSString *)callNumber
{
return [NSString stringWithFormat:@"%@ say:I LOVE YOU",[super callNumber]];
}
-(NSString *)sendMassage
{
return [NSString stringWithFormat:@"%@ say:I LOVE YOU",[super sendMassage]];
}
@end
最后,用客户端程序验证一下:
Phone *phone=[Iphone new];
NSLog(@"%@",phone.callNumber);
NSLog(@"%@",phone.sendMassage);
Content *content=[Content new];
[content setPhone:phone];
NSLog(@"%@",content.callNumber);
NSLog(@"%@",content.sendMassage);
打印:
2015-05-21 21:03:06.375 Decrotor[12220:1880459] Using iphone6plus call GF
2015-05-21 21:03:06.376 Decrotor[12220:1880459] Using iphone6plus send a message to GF
2015-05-21 21:03:06.376 Decrotor[12220:1880459] Using iphone6plus call GF say:I LOVE YOU
2015-05-21 21:03:06.376 Decrotor[12220:1880459] Using iphone6plus send a message to GF say:I LOVE YOU
OVER...