模板方法

Objective-C编程之道 iOS设计模式解析
iOS设计模式解析-工厂模式
iOS设计模式解析-抽象工厂模式
iOS设计模式解析-外观模式
iOS设计模式解析-中介者模式
iOS设计模式解析-观察者模式
iOS设计模式解析-装饰模式
iOS设计模式解析-责任链模式
iOS设计模式解析-模板方法
iOS设计模式解析-策略模式
iOS设计模式解析-享元模式
iOS设计模式解析-代码地址

何为模板方法模式

模板方法模式是面向对象软件设计中一种非常简单的设计模式,其基本思想是在抽象类的一个方法中定义“标准”算法,在这个方法中调用基本操作应由子类重载予以实现,这个方法被称为“模板”,因为方法定义的算法缺少一些特有的操作。

模板方法模式:定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使子类可以重定义算法的某些特定步骤而不改变改算法的结构

何时使用模板方法

在以下情形,应该考虑使用模板方法。

  • 需要一次性实现算法的不变部分,并将可变的行为留给子类来实现。
  • 子类的共同行为应该被提取出来放到公共类中,以避免代码重复。现有代码的差别应该被分离为新的操作。然后用一个调用这些新操作的模板方法来替换这些不同的代码。
  • 需要控制子类的扩展。可以定义一个在特定点调用“钩子”(hook) 操作的模板方法。子类可以通过对钩子操作的实现在这些点扩展功能。

注意:钩子操作给出了默认行为,子类可对其扩展。默认行为通常什么都不做。子类可以重载这个方法,为模板算法提供附加的操作。

具体使用

做简单的三明治,基本步骤应该像下面这样

  • 准备面包
  • 把面包放在盘子上
  • 往面包上加肉
  • 加调味料
  • 上餐
    定义一个AnySandwich类
#import 


@interface AnySandwich : NSObject 

- (void) make;

// Steps to make a sandwich
- (void) prepareBread;
- (void) putBreadOnPlate;
- (void) addMeat;
- (void) addCondiments;
- (void) extraStep;
- (void) serve;

@end
#import "AnySandwich.h"


@implementation AnySandwich

- (void) make
{
  [self prepareBread];
  [self putBreadOnPlate];
  [self addMeat];
  [self addCondiments];
  [self extraStep];
  [self serve];
}

- (void) putBreadOnPlate
{
  // We need first to put bread on a plate for any sandwich.
}

- (void) serve
{
  // Any sandwich will be served eventually.
}

#pragma mark -
#pragma Details will be handled by subclasses

- (void) prepareBread
{
  //Objectice-C的方法没有任何属性,可以要求子类必须进行重载,如果三明治不执行prepareBread、addMeat、addCondiments步骤,就不是三明治了,此时抛出一个异常是比较合理的。
  [NSException raise:NSInternalInconsistencyException 
              format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}

- (void) addMeat
{
  [NSException raise:NSInternalInconsistencyException 
              format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}

- (void) addCondiments
{
  [NSException raise:NSInternalInconsistencyException 
              format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
}
//钩子操作
- (void) extraStep{}

@end

定义子类ReubenSandwich制作三明治

#import 
#import "AnySandwich.h"

@interface ReubenSandwich : AnySandwich

- (void) prepareBread;
- (void) addMeat;
- (void) addCondiments;
- (void) extraStep;

// ReubenSandwich's specific operations
- (void) cutRyeBread;
- (void) addCornBeef;
- (void) addSauerkraut;
- (void) addThousandIslandDressing;
- (void) addSwissCheese;
- (void) grillIt;

@end
#import "ReubenSandwich.h"


@implementation ReubenSandwich

- (void) prepareBread
{
  [self cutRyeBread];
}

- (void) addMeat
{
  [self addCornBeef];
}

- (void) addCondiments
{
  [self addSauerkraut];
  [self addThousandIslandDressing];
  [self addSwissCheese];
}

- (void) extraStep
{
  [self grillIt];
}

#pragma mark -
#pragma mark ReubenSandwich Specific Methods

- (void) cutRyeBread
{
  // A Reuben sandwich requires two slices of rye bread
}

- (void) addCornBeef
{
  // ... add tons of corn beef
}

- (void) addSauerkraut
{
  // ... and sauerkraut.
}

- (void) addThousandIslandDressing
{
  // ... don't forget to put Thousand Island dressing
}

- (void) addSwissCheese
{
  // ... as well as some good Swiss cheese.
}

- (void) grillIt
{
  // finally it needs to be toasted.
}
@end

注意:此时extraStep钩子操作中添加了步骤,一般来说,默认的“钩子”方法什么都不做,而且“钩子”方法对子类来说是可选的,这个地方可以选,另外一种三明治也可以不选,

调用代码

- (void)viewDidLoad {
    [super viewDidLoad];
    AnySandwich * sandwich = [[AnySandwich alloc] init];
    [sandwich make];
}

此时明显是不对的,这个类只是定义了做三明治的方法,但有些步骤并没有实现,直接输出

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'You must override prepareBread in a subclass'

这样子调用,才是真正产生ReubenSandwich类型的三明治

- (void)viewDidLoad {
    [super viewDidLoad];
    AnySandwich * sandwich = [[ReubenSandwich alloc] init];
    [sandwich make];
}

你可能感兴趣的:(模板方法)