[转载]AS2实践设计模式(1):abstract factory模式

最初的动机还是看到JimLee写的几篇关于设计模式的文章,刚好自己这一阵考完了试,现在抽出时间来系统的学习设计模式,所以就用AS2来实践一下设计模式里面讲述的23个模式了。
AS2现在可以说是面向对象的,但是它所支持的面向对象特性还是比较简单的,有些像smalltalk,动态性比c++要强很多,用来实践设计模式还是绰绰有余的。
按照书的排布,第一个模式是abstract factory,个人的理解是,客户只需对工厂发布命令,具体的实现则由具体的工厂实现,关键一点,各个工厂的产品一致,这是一个应用的需求,同时也是她的特点。abstract factory很好的封装了一系列产品的创建一致性。
在我的例子里,用了快餐店的例子,McDonald和KFC,都提供了汉堡、可乐、薯条和冰激淋,因此例子中就由他们作为工厂了。
最开始的是snacketeria快餐店接口,它定义了McDonald和KFC的统一接口函数:
snacketeria.as
interface snacketeria
{
public function makeHamburg():Hamburg;
public function makeFry():Fry;
public function makeCola():Cola;
public function makeIceCream():IceCream;
public function getShopName():String;
}
接着分别定义了McDonald和KFC类,对快餐店接口进行实现:
McDonald.as
class McDonald implements snacketeria
{
private var _name:String;
public function makeHamburg():Hamburg
{
return new McHamburg();
}
public function makeFry():Fry
{
return new Fry();
}
public function makeCola():Cola
{
return new McCola();
}
public function makeIceCream():IceCream
{
return new IceCream();
}
function McDonald()
{
_name = "McDonald";
}
public function getShopName():String
{
return _name;
}
}
两者的实现差不多,最重要的是定义了借口所返回的产品的类型
kFC.as
class KFC implements snacketeria
{
private var _name:String;
public function makeHamburg():Hamburg
{
return new KFCHamburg();
}
public function makeFry():Fry
{
return new Fry();
}
public function makeCola():Cola
{
return new KFCCola();
}
public function makeIceCream():IceCream
{
return new IceCream();
}
function KFC()
{
_name = "KFC";
}
public function getShopName():String
{
return _name;
}
}
同时针对快餐店提供的食物我们有定义了一系列的类
首先是food类,它是所有食物的基类
food.as
class food
{
private var _name:String;
private var _price:Number;
private var _discount:Number;
private var _type:String;

public function set name(Name:String):Void
{
_name = Name;
}
public function set price(Price:Number):Void
{
_price = Price;
}
public function set discount(Discount:Number):Void
{
_discount = Discount;
}
public function set type(Type:String):Void
{
_type = Type;
}
public function get name():String
{
return _name;
}
public function get price():Number
{
return _price;
}
public function get discount():Number
{
return _discount;
}
public function get type():String
{
return _type;
}
function food()
{
_name = "General food";
_type = "food";
_price =0;
_discount =1;
}
public function getPrice():Number
{
return _price * _discount;
}
public function getInfo():Void
{
trace(_type +" Details:");
trace("Name:"+ _name);
trace("Price:"+_price);
trace("Discount:"+_discount);
}
}

(现在有一个想法,觉得对于类中的private属性,没有必要实现他们的setter/getter,因为本身作为private类型,
他们是不能在类的外部被直接操作的,所以getter/setter可以说没有用武之地, 还是直接定义setProperty和getProperty函数为好,
或者我对setter/getter函数的用户所知不全?)
然后分别是Hamburg汉堡、McHamburg麦当劳的汉堡、KFCHamburg、Cola、McCola、KFCCola、Fry薯条、IceCream这些食品类
Hamburg.as
class Hamburg extends food
{
function Hamburg()
{
_name  = "汉堡";
_price = 0;
_discount = 1;
_type = "Hamburg";
}
}
McHamburg.as
class McHamburg extends Hamburg
{
function McHamburg()
{
_name = "超级汉堡";
_price =5.5;
_discount = 0.8;
_type = "McDonald Hamburg";
}
}
KFCHamburg.as
class KFCHamburg extends Hamburg
{
function KFCHamburg()
{
_name = "无敌巨无霸";
_price = 10;
_discount = 0.9;
_type = "KFC Hamburg";
}
}
Cola.as
class Cola extends food
{
function Cola()
{
_name  = "可乐";
_price = 0;
_discount = 1;
_type = "Cola";
}
}
McCola.as
class McCola extends Cola
{
function McCola()
{
_name = "可口可乐";
_price =2.5;
_discount = 1;
_type = "McDonald Cola";
}
}
KFCCola.as
class KFCCola extends Cola
{
function KFCCola()
{
_name = "百事可乐";
_price =2.5;
_discount = 1;
_type = "KFC Cola";
}
}
Fry.as薯条类
class Fry extends food
{
function Fry()
{
_name  = "薯条";
_price = 5;
_discount = 1;
_type = "Fry";
}
}
可以认为两家的薯条是一样的,所以就定义了这一个类
冰激淋同样如是
IceCream.as
class IceCream extends food
{
function IceCream()
{
_name  = "冰激淋";
_price = 2;
_discount = 1;
_type = "Ice Cream";
}
}
好了,我们的类已经都定义好了,下面就是写一个例子来client来操作,姑且就称为order吧,有少许composite的思想
order.as
class order
{
private var _foods:Array;
private var _price:Number;
private var _shop:snacketeria;
function order(shop:String)
{
_foods = new Array();
_price = 0;
switch (shop)
{
case "McDonald":
_shop = new McDonald();
break;
case "KFC":
_shop = new KFC();
break;
default:
_shop = new snacketeria();
}
}
public function addFood(item:food,count:Number):Boolean
{
if (Math.floor(count) >0)
{
_foods.push({item:item,count:count});
return true;
}else
return false;

}
public function getTotal():Number
{
var index:Number = 0;
_price = 0;
for (index =0; index < _foods.length; index++)
{
_price += _foods[index].item.getPrice()*_foods[index].count;
}
return _price;
}
public function getInfo()
{
var index:Number = 0;
trace ("Your Orders Detail:");
trace (_shop.getShopName());
trace ("Foods:");
for (index =0; index < _foods.length; index ++)
{
_foods[index].item.getInfo();
trace ("Count:"+_foods[index].count);
}
trace ("");
trace ("Total Price:"+getTotal());
}
}

接下来创建一个flash,在第一帧输入下面的代码进行测试:
var shop:snacketeria = new McDonald();//先确定到哪家店去消费
var lunch:order = new order(shop.getShopName());//开始上午餐了
lunch.addFood(shop.makeHamburg(),3);//三份汉堡
lunch.addFood(shop.makeCola(),2);//两杯可乐
lunch.addFood(shop.makeIceCream(),2);//两个icecream
lunch.addFood(shop.makeFry(),1);//一份薯条
lunch.getInfo();
最后的输出应该是这样的:
Your Orders Detail:
McDonald
Foods:
McDonald Hamburg Details:
Name:超级汉堡
Price:5.5
Discount:0.8
Count:3
McDonald Cola Details:
Name:可口可乐
Price:2.5
Discount:1
Count:2
Ice Cream Details:
Name:冰激淋
Price:2
Discount:1
Count:2
Fry Details:
Name:薯条
Price:5
Discount:1
Count:1

Total Price:27.2


GoF在他们的书中所举的使用Abstract factory例子是关于界面的,当你要你的程序具有不同的界面风格,如mac、KDE、Windows等等不同的按钮、滚动条风格,你就可以使用Abstract模式,为不同的风格设立一个styleFactory,来分别建立不同的button,scrollbar;这个其实在flash程序中也是一个很好的应用,当需要flash具有不同的界面风格时,可以用这种方式。
同时,abstract factory的缺点是:扩展很麻烦。对于我的例子,假如McDonal和KFC同时推出了一款新的食物,例如pizza,那么我就必须建立三个类,general pizza类,McPizza,KFCPizza类,当然如果两个店的相同的话,一个类就足够了,但是还要修改factory的方法,添加makePizza的method,如果有遗漏的话就出问题了,这个是很难保证的。:(

文章出处:AS2实践设计模式(1):abstract factory模式
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章