解释器模式

       在我们给定一个语言,并定义它的语法和一个解释器,这个解释器用来标识语言中的句子,就是所谓的解释器模式。例如我们做一些字符串的替换,或者进行一些密文的解密,像特定的字符替换频率足够高的话,那么可以使用这种解释器模式来解决这种问题。

解释器模式类图:
avatar

       图中我们定义了抽象解释器类Expression,声明一个抽象的解释操作。TerminalExpression是继承抽象表达式的终结表达式,例子中是最后将所有字符转换成小写字符并输出,定义的NoterminalExpression是将”*”的符号替换成”@”符号,也就可以理解为这个类是处理非终结符解释器。我们使用这种模式更多的是对场景的具体使用,如果要解释的内容很多的话,需要创建很多的非终结符解释器类,易引起类的膨胀,一些复杂的文法解释会比较难以维护。使用这种模式可以很好的进行解释扩展,只需新增解释器类,在一些简单的文法上比较容易实现。

       TerminalExpression的实现

1
2
3
4
- (NSString *)interpretStr:(NSString *)string
{
return [string lowercaseString];
}

       NoterminalExpression的实现

1
2
3
4
- (NSString *)interpretStr:(NSString *)string
{
return [string stringByReplacingOccurrencesOfString:@"*" withString:@"@"];
}

本节工程示例

迭代器模式

       迭代器模式主要用于顺序访问集合对象的元素,不需要知道集合对象中的底层表示。将数据存储和遍历的职责分离,增加新的迭代器和数据都很方便,无须修改原有代码,我们也可以自己定义数据的遍历方式。

迭代器模式类图
avatar

       图中我们定义了两个抽象类,迭代器抽象类Iterator定义了遍历的方式,容器抽象类Container定义了获取迭代器的接口,具体的实现由FruitsIterator类来完成。这个例子我们在外部给容器类进行的赋值,我们可以给定内部设置成集合类,这样就无须暴露它的内部表示,在迭代器类中我们可以添加方法来提供多种遍历方式。在使用迭代器模式的时候,我们需要增加新的迭代的话,不仅要增加聚合类,也要添加相应的迭代器类,这样会使类的个数成对的增加,一定程度上增加的系统的复杂性。

       FruitsIterator的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
- (instancetype)initWithFruits:(NSArray *)fruits
{
if (self = [super init]) {
_fruits = fruits;
_index = 0;
}
return self;
}

- (NSString *)first;
{
return self.fruits.firstObject;
}

- (NSString *)next;
{
if (self.index + 1 < self.fruits.count) {
self.index ++;
return self.fruits[self.index];
}
return nil;
}

- (NSString *)current;
{
if (self.index < self.fruits.count) {
return self.fruits[self.index];
}
return nil;
}

- (BOOL)hasNext;
{
if (self.index + 1 < self.fruits.count) {
return YES;
}
return NO;
}

- (BOOL)isFirst;
{
if (self.index == 0) {
return YES;
}
return NO;
}

- (BOOL)isLast;
{
if (self.index == self.fruits.count - 1) {
return YES;
}
return NO;
}

本节工程示例

命令模式

       命令模式的定义是将请求封装成一个对象,从而可用不同的请求对客户进行参数化,对请求排队或记录请求日志,以及支持可撤销的操作。

命令模式类图:

avantar

如图定义了抽象的Receiver(接收者角色)和Command(命令角色),各自有自己的实际具体实现接收操作和命令操作,Invoker是命令的请求者,也是命令模式中的最重要角色,这个角色对各个命令进行控制。

Command1的实现

1
2
3
4
5
6
7
8
9
10
11
12
- (instancetype)initWithReceiver:(Receiver *)receiver
{
if (self = [super init]) {
_receiver = receiver;
}
return self;
}

- (void)execute
{
[self.receiver doSomething];
}

本节工程示例

状态模式

状态模式是允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。在一些情况下,一个对象的行为取决于其状态变化的属性,当这个对象和外部的事件产生互动时,它的内部状态会改变,同时使得系统的行为也发生变化。

状态模式类图:

avantar

图中定义了抽象状态类State,拥有开始和停止状态,Context所持有的状态在两种状态的改变下,它会产生的行为变化。使用这种方式我们可以灵活的添加新的状态和行为,也可以让多个环境对象共享一个状态对象,从而减少系统中的个数,但使用状态模式容易增加系统类和对象的个数。

其中StartState的实现

1
2
3
4
5
- (void)doSomethingWithContext:(Context *)context;
{
NSLog(@"运动状态");
[context setState:self];
}

其中StopState的实现

1
2
3
4
5
- (void)doSomethingWithContext:(Context *)context;
{
NSLog(@"停止状态");
[context setState:self];
}

本节工程示例

备忘录模式

备忘录模式主要用来存储另外一个对象内部状态的快照对象。用意是在不破坏封装的条件下,将一个对象的状态捕捉住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。

备忘录模式类图:

avantar

备忘录模式中有三个角色,一个备忘录角色(Memento)它主要用来存储备忘发起者角色的内部状态,备忘发起角色(Originator)创建一个备忘录,用来记录此刻它的内部状态,在需要的时候使用备忘录恢复内部状态,还有个备忘录管理者角色(Caretaker),它负责保存好备忘录,它不能对备忘录的内容进行操作或者检查。使用这种模式给用户提供了一种可以恢复状态的机制,使用户能够比较方便地回到历史的状态,同时实现了信息额封装,用户不需要关心状态的保护细节。保存状态容易消耗资源,使类的成员变量过多。

其中Originator的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- (Memento *)saveStateToMemento
{
return [[Memento alloc] initWithState:_state];
}

- (void)setState:(NSInteger)state
{
_state = state;
}

- (NSInteger)getState
{
return _state;
}

- (void)getStateFromMemento:(Memento *)memento
{
_state = [memento getState];
}

本节工程示例

模板方法模式

模板模式是定义一个抽象类,它公开定义了执行它的方法的方式/模板,它的子类可以按需要重新写方法实现,但调用将以抽象类中的定义方式进行。

享元模式类图:

avantar

如图定义了一个出去旅游类,定义了一些流程模板,打包、出游、游玩、返回这些旅游过程,其中我们使用了三套方案出行、汽车、飞机和火车,它们的交通方式都不一样,然后各自实现相应的步骤。

其中Travel的实现部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (void)package
{
NSLog(@"打包");
}
- (void)goToPlace
{
NSLog(@"出发");
}
- (void)play
{
NSLog(@"游玩");
}
- (void)backHome
{
NSLog(@"回家");
}

- (void)travel
{
[self package];
[self goToPlace];
[self play];
[self backHome];
}

本节工程示例