找回密码
 FreeOZ用户注册
查看: 15077|回复: 39
打印 上一主题 下一主题

[论坛技术] 我的实用设计模式之四-Simple Factory,Factory Method和Abstract Factory

[复制链接]
跳转到指定楼层
1#
发表于 24-4-2009 22:48:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?FreeOZ用户注册

x
这是我自己的一些想法,论坛里有好多高手,请指教。
Simple Factory
先从Simple Factory开始讲起,假设模拟一个电玩店的试玩系统,这个电玩店专卖出售PS3的游戏机和提供试玩服务,当一个用户想试玩的时候,需要选择一种游戏类型进行试玩,系统会选择生成其中一个游戏盘的对象:竞赛游戏(PS3RacingGameDisk),射击游戏(PS3ShootingGameDisk)以及格斗游戏(PS3FightingGameDisk),这些游戏盘子类都分别继承自同一个游戏盘抽象类AbstractGameDisk。

                               
登录/注册后可看大图

图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的实现。

                               
登录/注册后可看大图

图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

                               
登录/注册后可看大图

图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

                               
登录/注册后可看大图

图4
引入对具体各个Players的抽象类AbstractPlayer后,在程序中可以声明AbstractPlayer的引用,而具体的Player对象的实例化过程留给具体的Player类(PS3Player或者WiiPlayer)来实现。AbstractPlayer声明CreateGameDisk方法负责实例化AbstractGameDisk的子类对象,具体的Player类负责实例化具体的AbstractGameDisk的子类。这个Method(CreateGameDisk)的行为就是一个Factory,所以称为Factory Method。下面是一个典型的Factory Method的UML图。

                               
登录/注册后可看大图

图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和Factory Method解决了游戏盘(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

                               
登录/注册后可看大图

图6
以下为一个经典Abtract Factory的实现,用于对比参考

                               
登录/注册后可看大图

图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的想法,欢迎指教。
   
Jake's Blog in 博客园 -- 精简开发 无线生活

评分

参与人数 4威望 +100 收起 理由
flyspirit + 20 谢谢,就是太复杂了。
ubuntuhk + 30 加分!
coredump + 30 你太有才了!
dflovely + 20 强人,学习

查看全部评分

回复  

使用道具 举报

2#
 楼主| 发表于 26-4-2009 13:33:55 | 只看该作者
没人愿意k一下?
回复  

使用道具 举报

3#
发表于 26-4-2009 14:04:22 | 只看该作者

回复 #2 procoder 的帖子

对设计模式很有兴趣,不过从来没接触过,谢谢你的介绍!
回复  

使用道具 举报

4#
发表于 26-4-2009 14:56:39 | 只看该作者
怎么K? 讨论设计模式?  空心的菱形表示聚合,实心的菱形表示组合。可以参考一下《UML参考手册》中的说明。空心的菱形表示Wheel对象并不随Car的创建而创建,销毁而销毁. 实心菱形表示Department对象随Company对象的创建而创建,销毁而销毁。没有明白你为什么用这个放在你的uml图中。因为player并不和abstract disk有直接的聚合(或组合)关系,只是调用具体的子类对象。

看了你的文章,有点晕。好像和以前自己的理解有区别:
先简单讨论一下。
1. 简单工厂: 单独的creator类,送进去参数,返回abstruct product.(但实际上是concrete product). 我猜你第一个是不是想表达这个意思?

评分

参与人数 1威望 +20 收起 理由
procoder + 20 谢谢分享!

查看全部评分

回复  

使用道具 举报

5#
发表于 26-4-2009 15:01:25 | 只看该作者
补充一下,一般我们常用 static 的 createProduct (ptype type)在简单工厂中。
优点:client doesn't care 如何创建 concrete product, 解耦了。逻辑放在 creator 的 static createProdcut中。
缺点: creator 的 static createProdcut成了万能型选手。每次都要改这里。当产品有hierarchy时,死翘了。

评分

参与人数 1威望 +20 收起 理由
procoder + 20 谢谢分享!

查看全部评分

回复  

使用道具 举报

6#
发表于 26-4-2009 15:12:46 | 只看该作者
有点忘了,子类是否能继承基类的静态方法?你要是能确定就回复一下。
我印象是能继承,但无法override. 所以才导致factory method的出现。
刚才说完,static factory method (simple facotry)
接下来再谈: factory method
factory method中,creator 不再负责 create了,它当爸爸了。create concrete product 的脏活累活,由他的儿子(马仔)来干。

评分

参与人数 1威望 +20 收起 理由
procoder + 20 谢谢分享!

查看全部评分

回复  

使用道具 举报

7#
发表于 26-4-2009 15:32:01 | 只看该作者
因为不是static method所以可以继承并修改。concrete creator就可以自由繁殖了。好处是:
原来在client端:想要“你是电,你是光”
基类变量 = new Creator电();
物质(实际上指向电)=基类变量. create( ); //与static factory method 区别,不用传值。因为已经知道是Creator电()。

基类变量 = new Creator光();
物质(实际上指向光)=基类变量. create( ); //与static factory method 区别,不用传值。因为已经知道是Creator电()。

现在在client端:想要“你是电,你是光,你是唯一的神话”
三步搞定:
1. 唯一的神话:物质
2. Creator唯一的神话: 基类
3. client端加上:
基类变量 = new Creator唯一的神话();
物质(实际上指向唯一的神话)=基类变量. create( ); //与static factory method 区别,不用传值。因为已经知道是Creator唯一的神话()。

完全follow open-close principle. 这下世界清净了。

评分

参与人数 1威望 +30 收起 理由
coredump + 30 你太有才了!

查看全部评分

回复  

使用道具 举报

8#
发表于 26-4-2009 15:48:12 | 只看该作者
刚刚流得滑了几天,唉,人生难免踩上狗屎。用户要求听小沈阳版的,宋丹丹版。。。
用户:这个可以有,
DEV: 这个真没有
用户:没有?把你老板找来!
DEV: 没有
用户:没有?Only you...

我们piapai的昏了。大象,大象,你的需求为什么这么长?
无奈呀,我们请出了abstract facotry.
很简单:就是在creator中,加上不同的种类,以便让产生不同的盗版。

我的故事讲完了。
欢迎讨论
回复  

使用道具 举报

9#
 楼主| 发表于 26-4-2009 18:26:14 | 只看该作者
根据各方讨论,我把文章更新了,可见这里 我的实用设计模式之四-Simple Factory,Factory Method和Abstract Factory

[ 本帖最后由 procoder 于 26-4-2009 17:46 编辑 ]
回复  

使用道具 举报

10#
 楼主| 发表于 26-4-2009 18:38:09 | 只看该作者
原帖由 stgeorge 于 26-4-2009 13:56 发表
因为player并不和abstract disk有直接的聚合(或组合)关系,只是调用具体的子类对象。

我使用Aggregation因为考虑到player会把abstract disk作为一个成员变量保存起来,到底是Aggregation,Composition或者Dependency要看具体的应用。
两个类之间的关系,例如类A和B。
如果是B是A成员变量,而且BA的构造函数中生成(new),那么就是Composition。
如果是B是A成员变量,而且B不在A的构造函数中生成(new),而是在有需要的时候才new,那么就是Aggregation。
如果A在某个函数中使用了B作为局部变量,那么就是Dependency。

在经典的实现中一般画成DirectedAssociation,Composition和Aggregation都是Association的一种,看具体应用。
但是我想这里的Aggregation不影响模式的表述,因为这个只是Client和Factory的关系,模式准确与否,看Factory自己的Hierarcy。
回复  

使用道具 举报

11#
 楼主| 发表于 26-4-2009 18:40:41 | 只看该作者
原帖由 stgeorge 于 26-4-2009 13:56 发表
1. 简单工厂: 单独的creator类,送进去参数,返回abstruct product.(但实际上是concrete product). 我猜你第一个是不是想表达这个意思?

就是这个意思。
回复  

使用道具 举报

12#
发表于 26-4-2009 19:07:53 | 只看该作者
个人拙见,这些个模式还是太复杂。一个最常用的工厂模式就画出这么一个大图,那些二十几个模式我从来就没有同时想清楚过。
其实工厂模式就一个原理,为了把对象的接口和实现分开,搞一个控制器用来取对象。一句话不就完了,所以我们有个控制器类来控制这个事情。结果这些人把这个控制器类再给抽象化成接口和实现,居然又造出个模式,要按这个逻辑,我能造出无数个设计模式来,只能让人糊涂么。这些个模式太冗长了。当然我也不能肯定这么二十几个都没用,但始终觉得5,6个也就够了。

评分

参与人数 1威望 +9 收起 理由
procoder + 9 谢谢分享!only 9 point left.

查看全部评分

回复  

使用道具 举报

13#
发表于 26-4-2009 22:29:24 | 只看该作者

回复 #12 black_zerg 的帖子

问题的复杂度不同,采用的设计方案也不同。杀鸡用牛刀不好,杀牛用铅笔刀也很愚蠢。

评分

参与人数 1威望 +10 收起 理由
procoder + 10 谢谢分享!

查看全部评分

回复  

使用道具 举报

14#
 楼主| 发表于 27-4-2009 11:46:59 | 只看该作者

回复 #12 black_zerg 的帖子

模式确实是在那几个设计原则的基础上推导出来,GoF的模式只是对某些场景下的设计手法,不是所有常见都用得上,简单场景用简单的,我用得最多是Simple Factory,那个还不算GoF模式呢。Abstract Factory只是用在写数据库的wrapped class。ADO.net就是使用他的,如果在这一的场景下,用Abstract Factory非常方便,不用反而不好。
回复  

使用道具 举报

15#
 楼主| 发表于 27-4-2009 12:02:20 | 只看该作者
原帖由 stgeorge 于 26-4-2009 14:12 发表
有点忘了,子类是否能继承基类的静态方法?你要是能确定就回复一下。
我印象是能继承,但无法override. 所以才导致factory method的出现。
刚才说完,static factory method (simple facotry)
接下来再谈: facto ...

子类可以继承基类的静态方法,但是不能多态,static是编译时的,polomorphism是运行时的,但是这个不是“导致factory method的出现”的原因。“导致factory method的出现”的原因可以从设计原则“面向抽象编程而不是面向具体编程”推出。
回复  

使用道具 举报

16#
发表于 27-4-2009 19:51:40 | 只看该作者
faint. GOF. 读个关于GOF的开头就坚持不下去了。痛苦。

评分

参与人数 1威望 +10 收起 理由
procoder + 10 谢谢分享!

查看全部评分

回复  

使用道具 举报

17#
发表于 28-4-2009 12:52:47 | 只看该作者
你的例子很好,不过最后的关于Abstract Factory的图有点乱,我画了一个,仅供参考

评分

参与人数 2威望 +50 收起 理由
procoder + 20 你太有才了!
coredump + 30 谢谢分享! 果然清楚多了

查看全部评分

回复  

使用道具 举报

18#
发表于 28-4-2009 13:59:07 | 只看该作者
对模式很感兴趣,不过如果为了模式而模式就不是特别有必要了。

.net中,一般的面向接口编程的模版也已经非常不错了。

评分

参与人数 1威望 +10 收起 理由
procoder + 10 谢谢分享!

查看全部评分

回复  

使用道具 举报

19#
 楼主| 发表于 29-4-2009 09:49:01 | 只看该作者
thank you very much.
I have a updated UML for the Abstract Factory here.


                               
登录/注册后可看大图
回复  

使用道具 举报

20#
 楼主| 发表于 29-4-2009 09:52:27 | 只看该作者

回复 #18 glite 的帖子

I agree "为了模式而模式就不是有必要了", anybody knows it.
This writing I wrote just demonstrate when need to use, how to use. I am NOT talking about U SHOULD use it any time.
回复  

使用道具 举报

21#
 楼主| 发表于 29-4-2009 09:55:27 | 只看该作者
From Simple Factory to Abstract Factory, the requirements are changing. Which patterns should be use just depends on which scenario it is. No one said using patterns is always better than non-using cases.
回复  

使用道具 举报

22#
 楼主| 发表于 29-4-2009 10:00:34 | 只看该作者

回复 #17 hoopoos 的帖子

In this case, I can not use GameDevice as the abstract class, because AbstractGameConsole, AbstractJoystick and AbstractGameDisk have different methods. Player have to know about each single one(AbstractGameConsole, AbstractJoystick and AbstractGameDisk) and use their specific methods.

Anyway, Thank you very much. Your design is absolutely clearer than mine. Good on you.
回复  

使用道具 举报

23#
发表于 29-4-2009 10:55:22 | 只看该作者
我同意你的说法,不过,鉴于一个game device通常是3部分搭配组成,那么也可以换一个形式,只用一个factory method来创建,我的设计和你的区别在于,我的client是个老年人或是小孩子,不懂一个游戏机由主机,手柄,光盘,组成,他只知道说:给我一台Wii游戏机,现在最火的!。你的Client呢,是个懂行的玩家,他熟门熟路的说,老板,来个欧版的主机,日版的手柄,08版的Wii Sport!

Anyway,你已经表示了Simple Factory,Factory Method和Abstract Factory,谢谢你的分享,你可以继续你的模式之旅!

评分

参与人数 1威望 +10 收起 理由
procoder + 10 谢谢分享!

查看全部评分

回复  

使用道具 举报

24#
 楼主| 发表于 29-4-2009 13:53:49 | 只看该作者

回复 #23 hoopoos 的帖子

Thanks for your ideas. I will keep going, I hope we can communicate more about Design Patterns.
回复  

使用道具 举报

25#
发表于 30-4-2009 04:13:53 | 只看该作者
楼主,请问一下,澳洲那边,.net一般是如何去做架构以及设计的?

在我们目前正在准备开发的项目中,项目经理让我们采用微软的petshop4那样类似的设计,在这样的设计中,我个人认为多多少少也用到了一点简单工厂方面的东东。

恩,有点感触。。。其实真的感觉自己有点没出息,只知道跟着微软走啊走。
回复  

使用道具 举报

26#
 楼主| 发表于 30-4-2009 09:41:32 | 只看该作者

回复 #25 glite 的帖子

我现在主要做compact framework,我开发的产品设计部分与平台无关,就是说设计不考虑语言特性,实现的时候才考虑语言特性。当然做j2ee那些可能不一样,平台有自己的模式,基于一般GoF的扩展,如果你用petshop的话,多多少少会用到些模式,我觉得随着问题复杂度越大,用到模式的机会越多,例如你有数据库访问层,就会用到Abstract Factory。

Simple Factory用的很多,也是最常用的一个,我自己平常用的经验。可是Simple Facotory不是GoF的模式。

评分

参与人数 1威望 +10 收起 理由
glite + 10 谢谢分享!

查看全部评分

回复  

使用道具 举报

27#
 楼主| 发表于 30-4-2009 09:48:53 | 只看该作者
跟着微软走没什么不好的,我就比较喜欢做.net。一起进步吧。
回复  

使用道具 举报

28#
发表于 30-4-2009 12:29:01 | 只看该作者
我的意思是认为这些模式不精炼,就以工厂模式为例,几个工厂模式其实都一回事。
一个应用分解为三个,接口,实现,以及一个取对象的工厂。所以我倾向于把他们看做一个模式,比较好理解和掌握。 那些后来衍生出的东西根本就不能算新模式,抽象工厂这个模式无非是 取对象那个类再次用工厂模式分解一下,另外一个则是一个简单的参数化实现。当然这三个工厂模式本身算是很简单的,并不难理解,可是看到后面那么多,什么桥接什么的就看得很头大。模式本身应该是很精炼的,而并不是一个实现,应该更倾向于设计思路和原则。

评分

参与人数 1威望 +20 收起 理由
procoder + 20 谢谢分享!

查看全部评分

回复  

使用道具 举报

29#
发表于 30-4-2009 14:10:20 | 只看该作者
没有仔细看代码,看看UML图:
探讨:
1. 是不是应该在Abstract layer上增加interface, 如你所说,接口优于实现
再者你用Abstract layer应该以后会用templete method, 大多如此。而且一但用templete method, 势必不会public, 而会在Abstract layer里面做,这样你的Abstract layer就不全是接口了

2.GameCosole,GameDisk,GameStick应该可以做一个更大的抽象工厂,而非都用类似builder的方式

3.真的是个电玩系统, 可能用不到那么多的层次,看平台的限制.....我更倾向用Jython.....

评分

参与人数 1威望 +20 收起 理由
procoder + 20 谢谢分享!

查看全部评分

回复  

使用道具 举报

30#
 楼主| 发表于 30-4-2009 23:31:21 | 只看该作者

回复 #28 black_zerg 的帖子

根据GoF的定义,三个还是有不同的应用场景的,不是同一个。
回复  

使用道具 举报

您需要登录后才可以回帖 登录 | FreeOZ用户注册

本版积分规则

小黑屋|手机版|Archiver|FreeOZ论坛

GMT+11, 17-11-2024 05:42 , Processed in 0.068857 second(s), 63 queries , Gzip On, Redis On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表