8

因此,我一直在阅读有关 Objective-C 模板方法的内容,并试图了解它们的特别之处。据我了解,基类中的任何方法都可以被覆盖并且可以调用超级?那么模板方法不仅仅是覆盖基类中的方法吗?

如果我错了,你能解释一下模板方法模式是什么,你能提供一个例子吗?

4

3 回答 3

24

是的,模板模式不仅仅是覆盖基类中的方法。

当具体定义算法的轮廓时可以使用模板模式,但是算法的步骤是抽象的。这意味着可以以不同的方式实施这些步骤。但是,算法的大致轮廓预计不会改变。

我刚刚创建的一个例子:

class Life {

   public method goThroughTheDay(){
     goToWork();
     eatLunch();
     comeBackHome();
     programABitMore();
   }
   abstract method goToWork();
   abstract method eatLunch();
   abstract method comeBackHome();
   abstract method programABitMore();
}

class GoodLife extends Life {
   //override all the abstract methods here
}

//The client application
Life life = new GoodLife();
life.goThroughTheDay();

基本上,预计一天的结束方式是在 Life 类中具体定义的。但是,该过程的细节由子类(即GoodLife)负责。GoodLife 类将执行与可能的 ToughLife 类非常不同的步骤。

这种模式有一些变化;例如,一些步骤也可以具体定义。在示例中,eatLunch() 可以具体定义在 Life 类中;意味着子类不会改变这种行为。

如果您有一个可以以不同方式实现的相对复杂的算法,则该模式很有意义。

=======================================

在我的回答中,我不知何故错过了 Objective-C 的部分。这是它在 Objective-C 中的样子:

@interface Life : NSObject

- (void) goThroughTheDay;

- (void) goToWork; // Abstract
- (void) eatLunch; // Abstract
- (void) comeBackHome; // Abstract
- (void) programABitMore; // Abstract

@end

@implementation Life

- (void) goThroughTheDay {

    [self goToWork];
    [self eatLunch];
    [self comeBackHome];
    [self programABitMore];
}

- (void) goToWork { [self doesNotRecognizeSelector:_cmd]; }
- (void) eatLunch { [self doesNotRecognizeSelector:_cmd]; }
- (void) comeBackHome { [self doesNotRecognizeSelector:_cmd]; }
- (void) programABitMore { [self doesNotRecognizeSelector:_cmd]; }

@end

@interface GoodLife : Life

@end

@implementation GoodLife

- (void) goToWork { NSLog(@"Good Work"); }
- (void) eatLunch { NSLog(@"Good Lunch"); }
- (void) comeBackHome { NSLog(@"Good Comeback"); }
- (void) programABitMore { NSLog(@"Good Programming"); }

@end

Objective-C 没有对抽象类的内置支持,所以我使用该doesNotRecognizeSelector:方法解决了它。更多关于抽象类和 Objective-C 的细节可以在这里找到。

于 2011-11-16T04:18:31.470 回答
3

我想我应该给出一个更具体的 Objective-C 答案。您可以在苹果的Cocoa 设计模式页面上阅读 Cocoa 中使用的模板方法。一个例子是drawRect:模板方法。像其他模板方法一样,您永远不会自己直接调用模板方法。它由 调用setNeedsDisplay。这样做的目的是让框架优化绘图。如果您drawRect:直接调用自己,您最终可能会多次进行不必要的重绘。

In fact you should probably try to make every method you want to override in a subclass a template method. This reduce the problem of knowing whether you should call the base class implementation when you override and makes debugging easier. You can just put a breakpoint in the base class, instead of every overridden methods in the subclasses.

于 2012-07-16T14:03:43.287 回答
1

据我了解,基类中的任何方法都可以被覆盖并且可以调用超级?那么模板方法不仅仅是覆盖基类中的方法吗?

是的,这不仅仅是覆盖基类方法。模板方法是一种实现算法的方法,其中某些步骤依赖于子类。例如,考虑 Base 中的一个方法,它具有三个主要步骤,f1、f2 和 f3。每个步骤都包含许多语句。这里 f1 和 f3 在所有子类中都相同,但 f2 是子类相关的。那么在这里做什么呢?您可以在 f1 和 f3 的子类复制语句中覆盖整个方法,但这是一种浪费。所以你在子类中只提供 f2 。通过这种方式,您可以在基类中定义算法(执行 f1,然后执行 f2,然后执行 f3),但为子类 (f2) 提供覆盖挂钩。注意,基类中的模板方法是final的,所以子类不能改变算法,例如不能改变f1、f2、f3的顺序,任何子类都不能省略f1、f3步骤。

简而言之,模板方法模式不仅仅是覆盖,它是使用继承来处理一些特定的情况。这不是 Obj-C 特定的,我无法为您提供任何特定于 Obj-C 的内容。要全面了解此模式,我建议以下内容:

  1. GoF 的设计模式书
  2. 头部优先设计模式
  3. 维基百科关于模板方法的文章

网上也有大量的教程/文章。基本思想不依赖于 Obj-C。

于 2011-11-16T04:19:22.770 回答