[C#]我的实用设计模式之四-Simple Factory,Factory Method和Abs
2009-06-02 17:09
721 查看
Simple Factory
先从SimpleFactory开始讲起,假设模拟一个电玩店的试玩系统,这个电玩店专卖出售PS3的游戏机和提供试玩服务,当一个用户想试玩的时候,需要选择一种游戏类
型进行试玩,系统会选择生成其中一个游戏盘的对象:竞赛游戏(PS3RacingGameDisk),射击游戏
(PS3ShootingGameDisk)以及格斗游戏(PS3FightingGameDisk),这些游戏盘子类都分别继承自同一个游戏盘抽象类
AbstractGameDisk。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/14/4a03acdf8cf0ed41587ae2e83c305a1f.png)
图1
public
abstract
class
AbstractGameDisk
{
public
string
Name {
get
;
set
; }
public
abstract
void
Load();
}
public
class
PS3RacingGameDisk : AbstractGameDisk
{
public
override
void
Load()
{
Console.WriteLine(
"
Load PS3 racing game.
"
);
}
}
public
class
PS3ShootingGameDisk : AbstractGameDisk
{
public
override
void
Load()
{
Console.WriteLine(
"
Load PS3 shooting game.
"
);
}
}
public
class
PS3FightingGameDisk : AbstractGameDisk
{
public
override
void
Load()
{
Console.WriteLine(
"
Load PS3 fighting game.
"
);
}
}
public
enum
GameDiskType
{
RACING,
SHOOTING,
FIGHTING
}
public
class
PS3Player
{
public
void
PlayAGame(GameDiskType type)
{
//
Get a console
//
Get a joystick
//
create a game disk
AbstractGameDisk disk;
switch
(type)
{
case
GameDiskType.RACING:
disk
=
new
PS3RacingGameDisk();
break
;
case
GameDiskType.SHOOTING:
disk
=
new
PS3ShootingGameDisk();
break
;
case
GameDiskType.FIGHTING:
disk
=
new
PS3FightingGameDisk();
break
;
default
:
disk
=
null
;
break
;
}
//
insert disk to console
//
load game
//
play and enjoy it
}
}
代码1
从上述代码看,如果我们需要增加新的游戏盘,例如角色扮演游戏(RolePlayGameDisk),那么生成游戏盘部分(见注释create a game disk处)需要增加case分支,这里的对具体游戏盘对象实例化存在着变化的需求。根据设计原则 "封装变化(Encapsulate what varies)
"
对这一对象实例化的需求进行封装。 引入一个新的类来封装和处理对象生成的需求,这个类叫做PS3DiskFacotry。
public
class
PS3Player
{
public
void
PlayAGame(GameDiskType type)
{
//
Get a console
//
Get a joystick
//
create a game disk
AbstractGameDisk disk
=
PS3DiskFactory.CreateGameDisk(type);
//
insert disk to console
//
load game
//
play and enjoy it
}
}
public
sealed
class
PS3DiskFactory
{
public
static
AbstractGameDisk CreateGameDisk(GameDiskType type)
{
switch
(type)
{
case
GameDiskType.RACING:
return
new
PS3RacingGameDisk();
case
GameDiskType.SHOOTING:
return
new
PS3ShootingGameDisk();
case
GameDiskType.FIGHTING:
return
new
PS3FightingGameDisk();
default
:
return
null
;
}
}
}
代码2
从上面的代码看PS3DiskFactory专门负责游戏盘(AbstractGameDisk的具体子类)的实例化过程,当有新的
游戏盘增加时,也就是实例化过程的需求发生变化时,全部变化会单独发生在PS3DiskFactory里面,也就是可变化的需求被封装到一个类里面了,这
就是Simple Factory的实现。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/14/390027127020cc923076c8b7d9b3251c.png)
图2
由于对实例化需求的变化的封装,从图可见PS3DiskManager和具体的游戏盘类
(PS3RacingGameDisk,PS3ShootingGameDisk和PS3FightingGameDisk等)彻底的解
耦,PS3DiskManager只是依赖于他们共同的抽象类AbstractGameDisk和工厂类PS3DiskFactory。Simple
Factory的作用就是用来封装“对象实例化可变化的需求”。
Factory Method
随着这个电玩店的发展,店里开始支持Wii游戏机销售和试玩,原先的系统需要更新符合这一新需求。参考Simple Factory的实现,我们可以很快速的实现Wii的需求。public
class
WiiPlayer
{
public
void
PlayAGame(GameDiskType type)
{
//
Get a console
//
Get a joystick
//
create a game disk
AbstractGameDisk disk
=
WiiDiskFactory.CreateGameDisk(type);
//
insert disk to console
//
load game
//
play and enjoy it
}
}
public
sealed
class
WiiDiskFactory
{
public
static
AbstractGameDisk CreateGameDisk(GameDiskType type)
{
switch
(type)
{
case
GameDiskType.RACING:
return
new
WiiRacingGameDisk();
case
GameDiskType.SHOOTING:
return
new
WiiShootingGameDisk();
case
GameDiskType.FIGHTING:
return
new
WiiFightingGameDisk();
default
:
return
null
;
}
}
}
public
class
WiiRacingGameDisk : AbstractGameDisk
{
public
override
void
Load()
{
Console.WriteLine(
"
Load Wii racing game.
"
);
}
}
public
class
WiiShootingGameDisk : AbstractGameDisk
{
public
override
void
Load()
{
Console.WriteLine(
"
Load Wii shooting game.
"
);
}
}
public
class
WiiFightingGameDisk : AbstractGameDisk
{
public
override
void
Load()
{
Console.WriteLine(
"
Load Wii fighting game.
"
);
}
}
代码3
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/14/639826bc14f3e1d50ef5bd4ce9e303fa.png)
图3
第一眼看是不是很容易实现了新的需求?Copy & Paste,稍稍修改一下就完了。可是有没有发现两个Player类除了对GameDisk的实例化以外,其他的一模一样。我们引进第二个设计原则 "面向抽象编程,而不是面向具体编程(Depend on Abstractions, not on Concretions)"
,增加对各个具体Player的抽象类AbstractPlayer.Client面向的是Player的抽象类而不是具体的Player。
public
abstract
class
AbstractPlayer
{
public
void
PlayAGame(GameDiskType type)
{
//
Get a console
//
Get a joystick
//
create a game disk
AbstractGameDisk disk
=
CreateGameDisk(type);
//
insert disk to console
//
load game
//
play and enjoy it
}
protected
abstract
AbstractGameDisk CreateGameDisk(GameDiskType type);
}
public
class
PS3Player : AbstractPlayer
{
protected
override
AbstractGameDisk CreateGameDisk(GameDiskType type)
{
return
PS3DiskFactory.CreateGameDisk(type);
}
}
public
class
WiiPlayer : AbstractPlayer
{
protected
override
AbstractGameDisk CreateGameDisk(GameDiskType type)
{
return
WiiDiskFactory.CreateGameDisk(type);
}
}
代码4
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/14/63c0870cd57f52c25a867ef32706c881.png)
图4
引入对具体各个Players的抽象类AbstractPlayer后,在程序中可以声明AbstractPlayer的引用,而具体
的Player对象的实例化过程留给具体的Player类(PS3Player或者WiiPlayer)来实现。AbstractPlayer声明
CreateGameDisk方法负责实例化AbstractGameDisk的子类对象,具体的Player类负责实例化具体的
AbstractGameDisk的子类。这个Method(CreateGameDisk)的行为就是一个Factory,所以称为Factory
Method。下面是一个典型的Factory Method的UML图。
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/14/589d53c2064426eff2c1d8538f79ec7a.gif)
图5
从图5和图4可以看,AbstractPlayer就是一个Creator,而PS3Player和WiiPlayer是一个
ConcreteCreator,CreateGameDisk()就是FactoryMethod(),AbstractPlayer只是定义实例化方
法,但是不知道具体如何实例化对象,实例化那个具体的对象,这些都是由PS3Player和WiiPlayer负责的。在上述的实现,PS3Player
和WiiPlayer是借助于Simple Factory来实例化对象。
Factory
Method是一个推迟实例化的过程,在抽象类(Creator)定义实例化的行为(FactoryMethod),然后由具体的子类
(ConcreteCreator)决定具体实例化的对象。其实在OO中,抽象类负责定义行为(在C#中为Method或者Property),子类负责
实现行为,运行时动态调用不同行为称为 多态(polymorphism)。但是构造函数不能实现多态,Factory
Method就是解决对象实例化的多态问题。Factory Method的别名也叫Virtual
Constructor,为什么这样叫了,因为在C++里面实现多态都要定义Virtual
Function(虚函数),但是Constructor是不能定义为virtual的,Factory
Method恰恰解决这个问题,所以也就Virtual Constructor了。
Abstract Factory
上面讲述的Simple Factory和FactoryMethod解决了游戏盘(GameDisk)的对象的实例化过程,如果在Player中其他使用到的引用(例如游戏主机GameConsole和手柄
Joystick)都需要实现实例化不同的对象。那么就不仅仅需要CreateGameDisk(),而且需要CreateGameConsole()和
CreateJoystick()来实例化具体的对象。抽象类AbstractPlayer组合这些Factory Methods,实现如下。
public
abstract
class
AbstractPlayer
{
public
abstract
AbstractGameDisk CreateGameDisk(GameDiskType type);
public
abstract
AbstractGameConsole CreateGameConsole();
public
abstract
AbstractJoystick CreateJoystick();
}
public
class
PS3Player : AbstractPlayer
{
public
override
AbstractGameDisk CreateGameDisk(GameDiskType type)
{
return
PS3DiskFactory.CreateGameDisk(type);
}
public
override
AbstractGameConsole CreateGameConsole()
{
return
new
PS3Console();
}
public
override
AbstractJoystick CreateJoystick()
{
return
new
PS3Joystick();
}
}
public
class
WiiPlayer : AbstractPlayer
{
public
override
AbstractGameDisk CreateGameDisk(GameDiskType type)
{
return
WiiDiskFactory.CreateGameDisk(type);
}
public
override
AbstractGameConsole CreateGameConsole()
{
return
new
WiiConsole();
}
public
override
AbstractJoystick CreateJoystick()
{
return
new
WiiJoystick();
}
}
public
abstract
class
AbstractGameDisk
{
public
string
Name {
get
;
set
; }
public
abstract
void
Load();
}
public
abstract
class
AbstractGameConsole
{
public
void
InsertGameDisk(AbstractGameDisk disk) { }
public
void
PluginJoystick(AbstractJoystick joystick) { }
}
public
abstract
class
AbstractJoystick
{
}
public
class
PS3Console : AbstractGameConsole
{
}
public
class
PS3Joystick : AbstractJoystick
{
}
public
class
WiiConsole : AbstractGameConsole
{
}
public
class
WiiJoystick : AbstractJoystick
{
}
代码5
AbstractPlayer不再负责PlayAGame的功能,只是声明了一系列产品的实例化的Methods。AbstractPlayer还是Factory Method。 我们需要实现PlayAGame的功能,基于设计原则"组合优于继承(Favor Object composition over inheritance)"
,我们定义一个新的类(Player),然后把工厂类(AbstractPlayer)作为一个引用组合到这一个类里面,这就是Abstract Factory模式的实现。
public
enum
GameDevice
{
PS3,
WII
}
public
class
Player
{
private
AbstractPlayer playerFactory;
public
Player(GameDevice device)
{
switch
(device)
{
case
GameDevice.PS3:
playerFactory
=
new
PS3Player();
break
;
case
GameDevice.WII:
playerFactory
=
new
WiiPlayer();
break
;
}
}
public
void
PlayAGame(GameDiskType type)
{
//
Get a console
AbstractGameConsole console
=
CreateGameConsole();
//
Get a joystick
AbstractJoystick joystick
=
CreateJoystick();
console.PluginJoystick(joystick);
//
create a game disk
AbstractGameDisk disk
=
CreateGameDisk(type);
//
insert disk to console
console.InsertGameDisk(disk);
//
load game
//
play and enjoy it
}
private
AbstractGameDisk CreateGameDisk(GameDiskType type)
{
return
playerFactory.CreateGameDisk(type);
}
private
AbstractGameConsole CreateGameConsole()
{
return
playerFactory.CreateGameConsole();
}
private
AbstractJoystick CreateJoystick()
{
return
playerFactory.CreateJoystick();
}
}
代码6
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/14/3507afeba297ce865d7a77f75bd854e2.png)
图6
以下为一个经典Abtract Factory的实现,用于对比参考
![](https://oscdn.geek-share.com/Uploads/Images/Content/202003/14/b98c7462219f579235c2bec3308e6fd3.gif)
图7
Player(Client)完全不知道GameConsole,Joystick和GameDisk到底如何实例化的,这些都又具体工厂
(PS3Player或者WiiPlayer)来负责一系列相关联的产品(也就是对象)的实例化,这一系列相关联的产品称为产品族(product
family)。Player根据GameDevice借助AbstractPlayer实例化产品族,产品族下的所有产品具体协同工作,而Player
只是依赖于产品组的产品的抽象类而不是具体类,也就是说,产品族的替换不会影响Player类的PlayAGame()。这一特性适合可替换产品族的设
计,例如不同桌面主题的设计和不同数据库访问组件的设计,ADO.net的数据库访问层就是基于Abstract Factory模式设计的。
Player的构造函数中选择具体工厂也是用了条件选择(switch),这里可以通过Simple Factory来对具体工厂的实例化。
Abstract Factory有几个特点:
1.每次产生一系列相关联的产品,例如
WiiGameConsole,WiiJoystick和WiiRacingGameDisk等等,他们之间是协调工作,例如CreateGame有
InsertGameDisk方法,表示WiiGameConsole和WiiRacingGameDisk协调工作。
2.不同产品族直接的产品不可以相互替换,例如PS3Joystick不能用于WiiGameConsole。
3.
使用Abstract
Factory一般在产品族相当固定的情景下,例如XBox游戏机也是有GameConsole,Joystick和GameDisk,那么实现
XBoxPlayer等产品族就可以支持XBox游戏机,但是如果需要更改产品族的产品,例如某新型游戏机不使用GameDisk而是使用
HardDisk来Load游戏的话,那么现有的设计就不能支持这一新型游戏机。
这些我对Simple Factory,Factory Method和Abstract Factory的想法,欢迎指教。
相关文章推荐
- 我的实用设计模式之Simple Factory,Factory Method和Abstract Factory
- 设计模式之C#实现--FactoryMethod
- [转]C#设计模式(4)-Simple Factory Pattern
- C#设计模式(4)-Simple Factory Pattern
- C#设计模式(5)-Factory Method Pattern
- C#设计模式之Factory Method
- 设计模式之C#实现(三)FactoryMethod
- C#设计模式(4)-Simple Factory Pattern
- C#设计模式-Factory Method Pattern
- C# 设计模式-工厂方法(Factory Method)
- C#设计模式(5)-Factory Method Pattern
- C#设计模式(5)-Factory Method Pattern
- C#设计模式(4)-Simple Factory Pattern
- C#设计模式——工厂方法模式(Factory Method)
- C#设计模式(4)-Simple Factory Pattern
- C#设计模式系列:简单工厂模式(Simple Factory)
- 设计模式一 - Simple Factory, Factory Method, Abstract Factory以及Builder模式简述
- C#设计模式(4)-Simple Factory Pattern
- C#设计模式(4)-Simple Factory Pattern
- C#设计模式(5)-Factory Method Pattern