更新1:更新Factory Method部分,说明文中使用“参数化工厂方法”的实现,同时加入经典Factory Method的实现进行比较。

更新2:更新Abstract Factory部分,说明文中和Factory Method部分一样使用“定义可扩展的工厂”的实现,同时加入经典Abstract Factory的实现进行比较。

更新3:更新Abstract Factory部分,说明所有的抽象类(Abstract Classes)可以改为Interface。

Simple Factory

先从Simple Factory开始讲起,假设模拟一个电玩店的试玩系统,这个电玩店专卖出售PS3的游戏机以及相关配件以及提供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的实现。

Simple Factory就是把对象实例化过程的需求封装到一个Factory类里面,把实例化过程的变化限制到该Factory类里面。Simple Factory不是GoF的模式之一,却应用十分广泛,Abstract Factory等模式可以借助Simple Factory来实现。

图2
在上面图2上PS3DiskPlayer是一个Client类,由于对实例化需求的变化的封装,PS3DiskPlayer和具体的游戏盘类(PS3RacingGameDisk,PS3ShootingGameDisk和PS3FightingGameDisk等)彻底的解耦,PS3DiskPlayer只是依赖于他们共同的抽象类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,稍稍修改一下就ok了。可是有没有发现两个Player类除了对GameDisk的实例化不同以外,其他的一模一样。我们根据第二个设计原则 "面向抽象编程,而不是面向具体编程(Depend on Abstractions, not on Concretions)" ,增加对各个具体Player的抽象类AbstractPlayer。Client面向的是Player的抽象类而不是具体的Player类(如PS3Player和WiiPlayer)。

    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后,在Client中可以声明AbstractPlayer的引用,而具体的Player对象的实例化过程留给具体的Player类(PS3Player或者WiiPlayer)来实现。AbstractPlayer声明CreateGameDisk方法负责实例化AbstractGameDisk的子类对象,具体的Player类负责实例化具体的AbstractGameDisk的子类。这个Method(CreateGameDisk)的行为就是一个Factory,所以称为Factory Method。

由于在介绍Factory Method之前,已经介绍了Simple Factory,因此我在上述的实现里面直接使用了Simple Factory的两个工厂PS3DiskFactory和WiiDiskFactory负责对各个具体GameDisk类(PS3RacingGameDisk, PS3ShootingGameDisk,PS3FightingGameDisk以及WiiRacingGameDisk, WiiShootingGameDisk,WiiFightingGameDisk)对象的实例化,如果用经典的Factory Method实现,实现变成以下。

图5

如果使用经典Factory Method实现,每一个具体GameDisk类(PS3RacingGameDisk等)对象的实例化都分别有一个具体的工厂类(WiiRacingGameCreator等)来负责,的下面是一个典型的Factory Method的UML图,用于比较。

图6
从图5和图6可以看,AbstractPlayer就是抽象Creator,而WiiRacingGameCreator等为ConcreteCreator。AbstractPlayer定义了一个方法CreateGameDisk()就是FactoryMehod()。AbstractPlayer只是定义实例化方法,但是不知道具体如何实例化对象,实例化那个具体的对象,这些都是由WiiRacingGameCreator等ConcreteCreator来负责。

在代码4和图4的实现中PS3Player和WiiPlayer是一个ConcreteCreator,CreateGameDisk()就是FactoryMethod(),AbstractPlayer只是定义实例化方法,但是不知道具体如何实例化对象,实例化那个具体的对象,这些都是由PS3Player和WiiPlayer负责的,PS3Player和WiiPlayer是借助于Simple Factory来实例化对象。

根据GoF,图5和图4的两种方法都是符合Factory Method的,图5的方法为经典手法,图4的方法为“参数化工厂方法”,关于“参数化工厂方法”可以参考GoF第三章 3.3 FACTORY METHOD里面的第9节第2点。

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)负责PlayAGame的功能,而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

图7(原图6)

Player(Client)完全不知道GameConsole,Joystick和GameDisk这一系列的产品到底如何实例化的,这些都由具体工厂(PS3Player或者WiiPlayer)来负责一系列相关联的产品(也就是对象)的实例化,这一系列相关联的产品称为产品族(product family)。和图4的Factory Method实现一样,这里对GameDisk的生成还是借助了Simple Factory来完成。我把实现简化一下,使得这个实现更像经典的Abtract Factory的实现。Player借助AbstractPlayer实例化产品族,产品族下的所有产品具体协同工作,而Player只是依赖于产品族下产品的抽象类而不是具体类,也就是说,产品族的替换不会影响Player类的PlayAGame()。这一特性适合可替换产品族的设计,例如不同桌面主题的设计和不同数据库访问组件的设计,ADO.net的数据库访问层就是基于Abstract Factory模式设计的。

图8

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

图9

图8为简化了图7的设计,把PS3DiskFactory和WiiDiskFactory这两个Simple Factory去掉了,由PS3Player分别WiiPlayer直接生成各个具体GameDisk类(PS3RacingGameDisk, PS3ShootingGameDisk,PS3FightingGameDisk以及WiiRacingGameDisk, WiiShootingGameDisk,WiiFightingGameDisk)。图8是Abstract Factory的经典实现,而图7叫做“定义可扩展的工厂”,参见GoF第三章3.1 ABSTRACT FACTORY的第9节的第3点。

从图8和图9看Player就是Client,AbstractPlayer就是AbstractFactory,CreateGameDisk(),CreateGameConsole()和CreateJoystick()就是CreateProduct1()和CreateProduct2()。AbstractGameConsole,AbstractJoystick和AbstractGameDisk就是AbstractProduct1和AbstractProduct2。PS3Player和WiiPlayer为ConcreteFactory1和ConcreteFactory2负责生产AbstractGameConsole等抽象产品的具体产品,这些具体产品为PS3GameConsole,PS3Joystick和PS3RacingGameDisk等。

根据小猴子的建议在代码6可以看到所有的抽象类(Abstract Classes)只有定义需要子类实现方法,没有共同逻辑的实现方法,所以可以把全部的抽象类(Abstract Classes)使用Interface来实现。

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游戏的话,那么现有的设计就不能支持这一新型游戏机。

在代码6中Player中把抽象工厂类(AbstractPlayer)作为一个成员,在Player的构造函数中使用了条件选择(switch)生成具体工厂,这里可以通过Simple Factory来对具体工厂的实例化。

根据winter-cn的建议可以把工厂作为参数传递到Player里面,这样做Player就不再负责具体工厂的生成过程,这样Player的类需要耦合具体的工厂,其实两种方法都是可以的,这只是一个Client的行为。

这些我对Simple Factory,Factory Method和Abstract Factory的想法,欢迎指教。

Jake's Blog in 博客园 -- 精简开发 无线生活

转载于:https://www.cnblogs.com/procoder/archive/2009/04/24/1442920.html

我的实用设计模式之Simple Factory,Factory Method和Abstract Factory相关推荐

  1. 设计模式学习总结1 - 创建型1 - Abstract Factory抽象工厂模式

    AbstractFactory抽象工厂模式(创建型) 作用: 这种模式支持创建不同的对象,这些对象功能接近且一般都是在一起创建的.抽象工厂被具体化成不同的工厂来创建类似产品的不同产品.这种模式将类于使 ...

  2. 设计模式的征途—4.抽象工厂(Abstract Factory)模式

    上一篇的工厂方法模式引入了工厂等级结构,解决了在原来简单工厂模式中工厂类职责太重的原则,但是由于工厂方法模式的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,从而增加系统开销.那么,我们应该 ...

  3. 设计模式之笔记--抽象工厂模式(Abstract Factory)

    抽象工厂模式(Abstract Factory) 定义 抽象工厂模式(Abstract Factory),提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 类图 描述 多个抽象产品 ...

  4. 设计模式(3):抽象工厂模式(Abstract Factory Pattern)

    1.继续工厂方法模式 在工厂方法模式中,介绍了一个工厂类创建一中产品,所有的工厂类都是基于接口实现的,所有的产品也是基于接口实现的.这样当增加新的产品的时候只需要实现新的工厂类和新的产品类即可,满足了 ...

  5. 极速理解设计模式系列:10.抽象工厂模式(Abstract Factory Pattern)

    五个角色:抽象产品角色(AbstractProduct).具体产品角色(Product).抽象工厂角色(AbstractFactory).具体工厂角色(ConcreteFactory).客户端(Cli ...

  6. Factory Method vs Abstract Factory

    点开这篇着你已经大致对工厂方法有了一定的了解.但为什么依然对这两者的区别不是很明白,在搜索了一天.看了许多文章后我有了一点想法,在这里分享并记录一下. 引用SO的一段文字: One differenc ...

  7. 设计模式之十一:抽象工厂模式(Abstract Factory)

    抽象工厂模式: 提供了一个创建一系列相关的或相互依赖的对象的接口而不须要详细指定它们的类型. Provide an interface for creating families of related ...

  8. 我的实用设计模式 - Simple Factory和Reflection

    更新1:使用as转换数据类型. 在上篇文章 我的实用设计模式 - Simple Factory,Factory Method和Abstract Factory 讲述了Simple Factory,Fa ...

  9. 设计模式:Abstract Factory和Builder(比较区别,个人认为讲得很明白)

    如果说 Factory和Prototype是同一个层次的话,那么Abstract Factory和Builder就是更高一级的层次. 1 Abstact Factory 在上面的Factory类型中, ...

最新文章

  1. android 分区layout以及虚拟内存布局-小结
  2. aix ntp 配置_aix下开启ntp服务
  3. java设计模式----代理模式
  4. TLS协议、PKI、CA
  5. 躺着赚钱|闲鱼自动发货脚本|自动化|Auto.js
  6. 网络通讯协议——TCP/IP协议
  7. 斐讯 k3 设置 虚拟服务器,斐讯K3无线中继设置教程(无线扩展)
  8. 最简单的联想笔记本重装系统方法,一键重装系统图解
  9. 把北斗七星与北极星捡起来
  10. 【01】什么是概率图模型?
  11. 今日头条2018校招测试开发方向(第一批)详解
  12. SWFUpload 使用说明
  13. 豆瓣电影TOP250爬虫及可视化分析笔记
  14. 计算机考研就业率,21考研同学需谨慎,三个专业就业率持续走低,包括热门计算机专业...
  15. Tita OKRs-E 使OKR成为您企业DNA一部分
  16. 英语人名的含义(转)
  17. Future、FutureTask、CompletableFuture简介
  18. 【基础】信息时代与计算机
  19. Nvidia-smi简介
  20. vivo计算机的功能是什么意思啊,vivo新系统有啥新功能_vivo新系统有什么功能

热门文章

  1. 剖析Mysql查询性能和诊断间歇性问题
  2. dock模拟macos教程_如何设置macOS应用程序以最小化其Dock图标
  3. 数据百问系列:“未知”数据该如何处理?
  4. 未来世界的精彩,你难以想象
  5. 好用的 ScreenToGif gif录制
  6. [附源码]java+ssm计算机毕业设计基于mvc的天启网上购物系统xl8uh(源码+程序+数据库+部署)
  7. Java期末大作业——六级词汇学习系统
  8. MindNode 5.0.1 pro for mac 破解版
  9. 学校html列表代码,高考报名学校代码
  10. 达芬奇调色17安装教程(附安装步骤+图文步骤)