如何在ActionScript 3.0里使用工厂模式和模板方法模式(Factory and Template Method Patterns)
2008-09-27 15:23
906 查看
抽象类(Abstract Classes)
抽象类在工厂和模板方法模式里扮演着重要角色。虽然ActionScript 3.0并没有原生支持它们,但我们依然可以在ActipScript 3.0里套用抽象类和抽象方法的思想。一个抽象类就是一个总被用来继承且永不会直接被实例化的类。它的用途跟接口类相似,但有一个最大的不同之处就是:接口类只定义公有方法的名称而没有具体的执行(就像是只有函数名而没有函数体),但抽象类两者都有。
抽象类使用抽象方法,这些抽象方法没有具体的执行,只用作占位符。在其它语言,例如 C#、Java,你可以使用 abstract 关键字来声明抽象方法,它的子类必须重写这些抽象方法。但在ActionScript 3.0里并没有 abstract 关键字,所以我们得想办法解决此问题。
在ActionScript 3.0里使用抽象类,你必须知道两个特别的关键字:override 和 final。子类必须使用override关键字重写抽象类的方法,方法名称必须相同。使用final关键字来声明那些不被子类重写的方法,在模板方法模式里就用到final关键字了。
模板方法
定义在抽象类里的模板方法包含一些方案,这些方案来用组织抽象方法。请看以下这个抽象类,在initialize()方法里,我们定义 games 初始化的方式:
package com.peachpit.aas3wdp.factoryexample {
public class AbstractGame {
// 模板函数
public final function initialize():void {
createField();
createTeam("red");
createTeam("blue");
startGame();
}
public function createField():void {
throw new Error("Abstract Method!");
}
public function createTeam(name:String):void {
throw new Error("Abstract Method!");
}
public function startGame():void {
throw new Error("Abstract Method!");
}
}
}
在上面例子里,initialize() 方法是一个模板函数。它定义了 game 是这样初始化的:首先调用 createField() 方法,然后调用 createTeam() 方法来创建队伍(teams),最后调用 startGame() 方法。然而在这个抽象类里面,这几个函数都没干什么实际的事情。它们是给子类重写的,让子类来决定具体需要做的事情。抽象类都不能被直接实例化,而且抽象类的方法都必须被重写,所以在上面那三个方法里都放置了 throw 语句,这样就可以防止它们被直接调用了。
接下来我们创建一个 FootballGame 类来继承 AbstractGame 类。这个子类重写抽象类的方法,然后在 initialize() 方法里被调。
package com.peachpit.aas3wdp.factoryexample {
public class FootballGame extends AbstractGame {
public override function createField():void {
trace("Create Football Field");
}
public override function createTeam(name:String):void {
trace("Create Football Team Named " + name);
}
public override function startGame():void {
trace("Start Football Game");
}
}
}
正如你所看见的,FootballGame 类重写了 createField()、createTeam()以及startGame() 方法,使这些方法更适合 football。然而那个 initialize() 方法没有改变。你可以通过这种方式来写一个 BaseballGame和BastketballGame 类。可以像下面代码那样使用 FootballGame 类:
package com.peachpit.aas3wdp.factoryexample {
import com.peachpit.aas3wdp.factoryexample.FootballGame;
import flash.display.Sprite;
public class FactoryExample extends Sprite {
public function FactoryExample() {
// Create an instance of FootballGame
var game:FootballGame = new FootballGame();
// Call the template method defined in AbstractGame
game.initialize();
}
}
}
执行上面的代码输出如下。你可以看到,重写后的方法会在那个模板函数(initialize())里调用,这个模板函数没有改变。
Create Football Field
Create Football Team Named red
Create Football Team Named blue
Start Football Game
也许你会疑惑抽象类有什么用,现在你应该明白了一些,这样做的好处,很显然,扩展性强,以后 createField()、createTeam()以及startGame() 内容需要更改,我们只要再创建一个子类就可以,不必修改其他应用代码。
工厂方法
现在我们拿上文所举的模板方法例子(点击这里)来说一下工厂方法。很普遍的做法是在模板方法里应用工厂方法。
在上文所说的例子里,createField() 方法并没有返回任何东西;它只输出“Create Football Field”。让我们来改一下它,让它可以创建并返回一个field对象。因为不同的游戏有不同的field类型,所以我们将要创建一个叫 IField 的接口类,所以field类都会实现这个接口。以下这个接口类定义一个 drawField() 方法:
package com.peachpit.aas3wdp.factory {
public interface IField {
function drawField():void;
}
}
接下来我们新建一个 FootballField 类来实现 IField 接口。FootballField 类定义如下:
package com.peachpit.aas3wdp.factoryexample {
import com.peachpit.aas3wdp.factoryexample.IField;
public class FootballField implements IField {
public function drawField():void {
trace("Drawing the Football Field");
}
}
}
工厂方法的目的是连接两个或以上分离但相关的类层次结构。在这个例子里,最顶层的是 AbstractGame 类,它有这些子类:FootballGame、BaseballGamet和BastketballGame类。然后第二层的是 IField 接口类,这些类实现这个接口:FootballField、BaseballField和BasketballField类。这个 abstractGame和IField对象是相关的,但它们具体的实例化视它们的子类而定。下图表示了这些类的层次结构:
注意下面的 createField() 和 initialize() 方法,createField() 方法是一个工厂方法,它返回一个实现IField接口的对象。请看:
package com.peachpit.aas3wdp.factoryexample {
import com.peachpit.aas3wdp.factoryexample.IField;
public class AbstractGame {
// 模板方法
public final function initialize():void {
var field:IField = createField();
field.drawField();
createTeam("red");
createTeam("blue");
startGame();
}
// 工厂方法
public function createField():IField{
throw new Error("Abstract Method!");
}
public function createTeam(name:String):void {
throw new Error("Abstract Method!");
}
public function startGame():void {
throw new Error("Abstract Method!");
}
}
}
这个抽象类和里面的模板方法都是匿名的,具体需要执行的事情在子类里定义。请看以下的 FootballField 类:
package com.peachpit.aas3wdp.factory {
import com.peachpit.aas3wdp.factory.FootballField;
import com.peachpit.aas3wdp.factory.IField;
public class FootballGame extends AbstractGame {
public override function createField():IField {
return new FootballField();
}
public override function createTeam(name:String):void {
trace("Create Football Team Named " + name);
}
public override function startGame():void {
trace("Start Football Game");
}
}
}
运行以上例子,会输出如下:
Drawing the Football Field
Create Football Team Named red
Create Football Team Named blue
Start Football Game
——————————————————————————–
简单工厂
请注意,厂模式和工厂方法模式不同,以下这个为简单工厂模式:
package com.peachpit.aas3wdp.factoryexample {
public class GameFactory {
public static function createGame(gameType:String):IGame {
switch(gameType){
case "football":
return new FootballGame();
case "baseball":
return new BaseballGame();
case "basketball":
default:
return new BasketballGame();
}
}
}
}
抽象类在工厂和模板方法模式里扮演着重要角色。虽然ActionScript 3.0并没有原生支持它们,但我们依然可以在ActipScript 3.0里套用抽象类和抽象方法的思想。一个抽象类就是一个总被用来继承且永不会直接被实例化的类。它的用途跟接口类相似,但有一个最大的不同之处就是:接口类只定义公有方法的名称而没有具体的执行(就像是只有函数名而没有函数体),但抽象类两者都有。
抽象类使用抽象方法,这些抽象方法没有具体的执行,只用作占位符。在其它语言,例如 C#、Java,你可以使用 abstract 关键字来声明抽象方法,它的子类必须重写这些抽象方法。但在ActionScript 3.0里并没有 abstract 关键字,所以我们得想办法解决此问题。
在ActionScript 3.0里使用抽象类,你必须知道两个特别的关键字:override 和 final。子类必须使用override关键字重写抽象类的方法,方法名称必须相同。使用final关键字来声明那些不被子类重写的方法,在模板方法模式里就用到final关键字了。
模板方法
定义在抽象类里的模板方法包含一些方案,这些方案来用组织抽象方法。请看以下这个抽象类,在initialize()方法里,我们定义 games 初始化的方式:
package com.peachpit.aas3wdp.factoryexample {
public class AbstractGame {
// 模板函数
public final function initialize():void {
createField();
createTeam("red");
createTeam("blue");
startGame();
}
public function createField():void {
throw new Error("Abstract Method!");
}
public function createTeam(name:String):void {
throw new Error("Abstract Method!");
}
public function startGame():void {
throw new Error("Abstract Method!");
}
}
}
在上面例子里,initialize() 方法是一个模板函数。它定义了 game 是这样初始化的:首先调用 createField() 方法,然后调用 createTeam() 方法来创建队伍(teams),最后调用 startGame() 方法。然而在这个抽象类里面,这几个函数都没干什么实际的事情。它们是给子类重写的,让子类来决定具体需要做的事情。抽象类都不能被直接实例化,而且抽象类的方法都必须被重写,所以在上面那三个方法里都放置了 throw 语句,这样就可以防止它们被直接调用了。
接下来我们创建一个 FootballGame 类来继承 AbstractGame 类。这个子类重写抽象类的方法,然后在 initialize() 方法里被调。
package com.peachpit.aas3wdp.factoryexample {
public class FootballGame extends AbstractGame {
public override function createField():void {
trace("Create Football Field");
}
public override function createTeam(name:String):void {
trace("Create Football Team Named " + name);
}
public override function startGame():void {
trace("Start Football Game");
}
}
}
正如你所看见的,FootballGame 类重写了 createField()、createTeam()以及startGame() 方法,使这些方法更适合 football。然而那个 initialize() 方法没有改变。你可以通过这种方式来写一个 BaseballGame和BastketballGame 类。可以像下面代码那样使用 FootballGame 类:
package com.peachpit.aas3wdp.factoryexample {
import com.peachpit.aas3wdp.factoryexample.FootballGame;
import flash.display.Sprite;
public class FactoryExample extends Sprite {
public function FactoryExample() {
// Create an instance of FootballGame
var game:FootballGame = new FootballGame();
// Call the template method defined in AbstractGame
game.initialize();
}
}
}
执行上面的代码输出如下。你可以看到,重写后的方法会在那个模板函数(initialize())里调用,这个模板函数没有改变。
Create Football Field
Create Football Team Named red
Create Football Team Named blue
Start Football Game
也许你会疑惑抽象类有什么用,现在你应该明白了一些,这样做的好处,很显然,扩展性强,以后 createField()、createTeam()以及startGame() 内容需要更改,我们只要再创建一个子类就可以,不必修改其他应用代码。
工厂方法
现在我们拿上文所举的模板方法例子(点击这里)来说一下工厂方法。很普遍的做法是在模板方法里应用工厂方法。
在上文所说的例子里,createField() 方法并没有返回任何东西;它只输出“Create Football Field”。让我们来改一下它,让它可以创建并返回一个field对象。因为不同的游戏有不同的field类型,所以我们将要创建一个叫 IField 的接口类,所以field类都会实现这个接口。以下这个接口类定义一个 drawField() 方法:
package com.peachpit.aas3wdp.factory {
public interface IField {
function drawField():void;
}
}
接下来我们新建一个 FootballField 类来实现 IField 接口。FootballField 类定义如下:
package com.peachpit.aas3wdp.factoryexample {
import com.peachpit.aas3wdp.factoryexample.IField;
public class FootballField implements IField {
public function drawField():void {
trace("Drawing the Football Field");
}
}
}
工厂方法的目的是连接两个或以上分离但相关的类层次结构。在这个例子里,最顶层的是 AbstractGame 类,它有这些子类:FootballGame、BaseballGamet和BastketballGame类。然后第二层的是 IField 接口类,这些类实现这个接口:FootballField、BaseballField和BasketballField类。这个 abstractGame和IField对象是相关的,但它们具体的实例化视它们的子类而定。下图表示了这些类的层次结构:
注意下面的 createField() 和 initialize() 方法,createField() 方法是一个工厂方法,它返回一个实现IField接口的对象。请看:
package com.peachpit.aas3wdp.factoryexample {
import com.peachpit.aas3wdp.factoryexample.IField;
public class AbstractGame {
// 模板方法
public final function initialize():void {
var field:IField = createField();
field.drawField();
createTeam("red");
createTeam("blue");
startGame();
}
// 工厂方法
public function createField():IField{
throw new Error("Abstract Method!");
}
public function createTeam(name:String):void {
throw new Error("Abstract Method!");
}
public function startGame():void {
throw new Error("Abstract Method!");
}
}
}
这个抽象类和里面的模板方法都是匿名的,具体需要执行的事情在子类里定义。请看以下的 FootballField 类:
package com.peachpit.aas3wdp.factory {
import com.peachpit.aas3wdp.factory.FootballField;
import com.peachpit.aas3wdp.factory.IField;
public class FootballGame extends AbstractGame {
public override function createField():IField {
return new FootballField();
}
public override function createTeam(name:String):void {
trace("Create Football Team Named " + name);
}
public override function startGame():void {
trace("Start Football Game");
}
}
}
运行以上例子,会输出如下:
Drawing the Football Field
Create Football Team Named red
Create Football Team Named blue
Start Football Game
——————————————————————————–
简单工厂
请注意,厂模式和工厂方法模式不同,以下这个为简单工厂模式:
package com.peachpit.aas3wdp.factoryexample {
public class GameFactory {
public static function createGame(gameType:String):IGame {
switch(gameType){
case "football":
return new FootballGame();
case "baseball":
return new BaseballGame();
case "basketball":
default:
return new BasketballGame();
}
}
}
}
相关文章推荐
- 如何让孩子爱上设计模式 ——24.模板方法模式(Template Method Pattern)
- JAVA设计模式——工厂方法(Factory Method)模式
- 工厂方法(Factory Method)模式
- C#回顾 - 7.如何使用反射实现工厂模式?
- 使用模板方法设计模式处理DAO中的查询方法
- 设计模式-创建型模式之 Factory Method(工厂方法)
- artTemplate-3.0复杂对象的遍历与使用方法
- Net设计模式实例之模板方法模式(Template Mothed Pattern)
- 详解设计模式中的模板方法模式及在C++中的使用
- 如何通过使用 DataReader GetSchemaTable 方法和 C#.net 检索列模式
- 设计模式之模板方法模式(Template)
- Net设计模式实例之模板方法模式(Template Mothed Pattern)
- Java技术_每天掌握一种设计模式(003)_使用场景及简单实例(创建型:工厂方法)
- 简单工厂模式(静态工厂方法(Static Factory Method)模式)
- Java设计模式圣经连载(02)-工厂方法(Factory Method)模式
- ASP.NET2.0中的GRIDVIEW控件在使用TemplateField中的LinkButton时如何在RowCommand事件中找到当前行index的方法
- 关于动态代理---模板方法模式,工厂模式,依赖倒转
- C++ - 模板(template)中typename的使用方法
- 面向对象:工厂方法(Factory Method)模式
- Java设计模式二:抽象工厂模式(Abstract Factory)/工厂方法(Factory Method)