IOS设计架构模式:责任链模式和模板模式

2019-04-14 15:30发布

一、责任链模式

1、何为责任链?

       责任链模式的主要思想是,将发送者和接收者解耦,接受者对象引用了同一类型的另一个对象,形成一条链。链中的每个对象实现了同样的方法,处理对链中第一个对象发起的同一个请求。如果一个对象不知道如何处理请求,它就把请求传递给下一个响应者。         责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间发生耦合。此模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

2、何时使用责任链模式?

       a、有多个对象可以处理请求,而处理程序只有在运行时才能确定。        b、向一组对象发出请求,而不想显示指定处理请求的特定处理程序。

3、怎么使用责任链模式?

        假定我们要开发一款游戏,里面的每个人物都可以通过做任务赚取点数来升级防御道具。防御道具可以使用攻击盔甲或者魔抗盔甲。每种形式的防御只能应付一种特定的攻击,如果防御道具不认识一种进攻,它就把进攻的作用传递给下一个会响应它的实体。比如,盔甲1不知道如何对付对手的攻击,所以把它传给下一个盔甲,盔甲2。盔甲2刚好知道如何对付这次攻击,化解了人物可能受到的损伤。由于某种原因,如果没有盔甲可以对这次攻击做出响应,攻击的作用最终会传到人物。人物对攻击做出响应时,会表现为一定程度的损伤。         这种只让每个独立的防御道具对特定类型的攻击做出相应的机制,简化了人物使用各种防御道具的复杂性。每种盔甲各自负责非常特定的功能。这就是责任链模式的作用所在。         下面我们将使用责任链模式实现这个设计,假设有两种防御:攻击盔甲和魔抗盔甲。它们都只能按照设计对付某些攻击。攻击盔甲可以防御来自武器的攻击,魔抗盔甲可以防御来自魔法的攻击。人物也是响应链的一部分,因此它也应该跟其他防御道具具有共同的行为,对攻击做出响应。         如上图所示,GongJi是发送者,FangYu是接收者,先创建人对象(接收者),再给人穿上魔抗盔甲(接收者),接着再给穿上武器盔甲(接收者),形成责任链,最后进行攻击(发送者发送请求)。 接收者类: Handler.h #import #import "GongJi.h" @interface Handler : NSObject // 下一个响应者 @property (nonatomic, strong) Handler *nextHandler; // 处理请求的接口 - (void)handleRequest:(GongJi *)request; @end Handler.m #import "Handler.h" @implementation Handler - (void)handleRequest:(GongJi *)attack { // 如果不能响应, 就把请求转发给successor来处理就行了 [self.nextHandler handleRequest:attack]; } @end Person.h #import "Handler.h" @interface Person : Handler @end Person.m #import "Person.h" @implementation Person - (void)handleRequest:(GongJi *)request { NSLog(@"被--%@--伤害到了",[request class]); } @end MoKangKuiJia.h #import "Handler.h" @interface MoKangKuiJia : Handler @end MoKangKuiJia.m #import "MoKangKuiJia.h" #import "MoFa.h" @implementation MoKangKuiJia -(void)handleRequest:(GongJi *)request { if ([request isKindOfClass:[MoFa class]]) { NSLog(@"2.攻击没有通过这个魔抗盔甲"); } else { NSLog(@"2.不是魔法攻击,防不住,其它去处理---%@", [MoFa class]); [self.nextHandler handleRequest:request]; } } @end KuiJia.h #import "Handler.h" @interface KuiJia : Handler @end KuiJia.m #import "KuiJia.h" #import "WuQi.h" @implementation KuiJia -(void)handleRequest:(GongJi *)request { if ([request isKindOfClass:[WuQi class]]) { NSLog(@"1.攻击没有通过这个盔甲"); } else { NSLog(@"1.不是剑攻击,防不住,其它去处理---%@", [WuQi class]); [self.nextHandler handleRequest:request]; } } @end 发送者类: GongJi.h #import @interface GongJi : NSObject @end GongJi.m #import "GongJi.h" @implementation GongJi @end WuQi.h #import "GongJi.h" @interface WuQi : GongJi @end WuQi.m #import "WuQi.h" @implementation WuQi @end MoFa.h #import "GongJi.h" @interface MoFa : GongJi @end MoFa.m #import "MoFa.h" @implementation MoFa @end ShanDian.h #import "GongJi.h" @interface ShanDian : GongJi @end ShanDian.m #import "ShanDian.h" @implementation ShanDian @end 业务对象: ViewController.h #import @interface ViewController : UIViewController @end ViewController.m #import "ViewController.h" #import "KuiJia.h" #import "MoKangKuiJia.h" #import "Person.h" #import "WuQi.h" #import "MoFa.h" #import "ShanDian.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // 1.创建人物 Handler *person = [[Person alloc] init]; // 2.增加魔法盾牌 Handler *moKangKuiJia = [[MoKangKuiJia alloc] init]; moKangKuiJia.nextHandler = person; // 3.穿盔甲 Handler *kuiJia = [[KuiJia alloc] init]; kuiJia.nextHandler = moKangKuiJia; // 1.武器攻击 GongJi *wuqi = [[WuQi alloc] init]; [kuiJia handleRequest:wuqi]; // 2.魔法攻击 GongJi *mofa = [[MoFa alloc] init]; [kuiJia handleRequest:mofa]; // 3.闪电攻击 GongJi *sd = [[ShanDian alloc] init]; [kuiJia handleRequest:sd]; } @end 这个例子演示了如何使用责任链模式,来简化人物处理各种攻击的编码和逻辑。如果不用这个模式,防御逻辑很可能都塞到一个类中(比如Person),代码会乱成一团的。

二、模板模式

1、概念描述

        模板方法模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。         通俗来讲就是:定义一个父类,有父类定义接口规范,然后不同的行为在子类中实现。这样一方面提高了代码的复用性,另一方面还可以利用面向对象的多态性,在运行时选择一种具体子类。模板模式是一种基于继承的代码复用技术,是一种类行为型模式。模板模式应该是最简单的一种设计模式,只存在继承关系,代码也相对简单。

2、使用场景

  • 相同的算法放在一个类中(父类)将算法变化的部分放在子类中。
  • 子类公共的算法放在一个公共类中,避免代码重复。

3、代码实现

模板类: Game.h #import @interface Game : NSObject // 初始化游戏 - (void)initGame; // 暂停操作 - (void)pause; // 游戏存储 - (void)gameSave; // 退出游戏 - (void)exitGame; // 开始游戏 - (void)startPlay; @end Game.m #import "Game.h" @implementation Game // 初始化游戏 - (void)initGame { } // 暂停操作 - (void)pause { } // 游戏存储 - (void)gameSave { } // 退出游戏 - (void)exitGame { } // 开始游戏 - (void)startPlay { } @end 实现类继承于模板类: Football.h #import "Game.h" @interface Football : Game @end Football.m #import "Football.h" @implementation Football // 初始化游戏 - (void)initGame { NSLog(@"init football"); } // 暂停操作 - (void)pause { NSLog(@"pause football"); } // 游戏存储 - (void)gameSave { NSLog(@"gameSave football"); } // 退出游戏 - (void)exitGame { NSLog(@"exitGame football"); } // 开始游戏 - (void)startPlay { NSLog(@"startPlay football"); } @end Baskeball.h #import "Game.h" @interface Baskeball : Game @end Baskeball.m #import "Baskeball.h" @implementation Baskeball // 初始化游戏 - (void)initGame { NSLog(@"init Baskeball"); } // 暂停操作 - (void)pause { NSLog(@"pause Baskeball"); } // 游戏存储 - (void)gameSave { NSLog(@"gameSave Baskeball"); } // 退出游戏 - (void)exitGame { NSLog(@"exitGame Baskeball"); } // 开始游戏 - (void)startPlay { NSLog(@"startPlay Baskeball"); } @end 业务类: ViewController.m #import "ViewController.h" #import "Football.h" #import "Baskeball.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 足球游戏 Game *footballGame = [Football new]; [footballGame initGame]; [footballGame startPlay]; [footballGame gameSave]; [footballGame pause]; [footballGame exitGame]; // 篮球游戏的创建 Game *baskeballGame = [Baskeball new]; [baskeballGame initGame]; [baskeballGame startPlay]; [baskeballGame gameSave]; [baskeballGame pause]; [baskeballGame exitGame]; } @end

4、模板模式的优点

  • 封装不变部分,扩展可变部分。即把认为不变部分的算法封装到父类实现,而可变部分的则可以通过继承来继续扩展
  • 提取公共部分代码,便于维护
  • 行为由父类控制,子类实现

5、模板模式的缺点

  • 按照平时的设计习惯,抽象类负责最抽象、最一般的事物属性和方法,实现类完成具体的事物属性和方法,但是模版方法模式却颠倒了,抽象类定义了部分抽象方法,由子类实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响,这在复杂的项目中,会带来代码阅读的难度
  • 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。