设计模式(2)工厂方法模式(Factory Method)

设计模式(0)简单工厂模式html

设计模式(1)单例模式(Singleton)git

源码地址github

0 工厂方法模式简介

0.0 工厂方法模式定义

工厂方法模式是在简单工厂模式基础上,为解决更复杂的对象建立问题而衍生进化出来的一种建立型模式。设计模式

工厂方法模式的核心思想是定义一个用于建立对象的接口,让其子类去决定去实例化哪一个具体类的对象,工厂方法模式可使一个类的实例化动做延迟到其子类。spa

工厂方法模式结构图以下设计

1

0.1 工厂方法模式应用场景

还接着祭坛生产英雄的示例,咱们已经在简单工厂模式一文中经过建立简单工厂方法类,来实现暗夜精灵种族4个英雄的建立code

/// <summary>
 /// 建立英雄的静态方法
 /// </summary>
 /// <param name="heroName">英雄名称</param>
 /// <returns></returns>
 public static IHero CreateHero(string heroName)
 {
     switch (heroName)
     {
         case "DH":
             return new DH();
         case "WD":
             return new WD();
         case "KOG":
             return new KOG();
         case "POM":
             return new POM();
         default:
             return null;
     }
 }

假设如今咱们要建立不死族的英雄怎么办呢,若是依然使用简单工厂方法类,则首先须要实现不死族四个英雄类。htm

/// <summary>
/// 死亡骑士
/// </summary>
public class DK : IHero
{
    /// <summary>
    /// 秀出本身的技能
    /// </summary>
    public void ShowSkills()
    {
        Console.WriteLine("我是死亡骑士,我会死亡缠绕、死亡契约、邪恶光环和操纵死尸。");
    }
}
/// <summary>
/// 巫妖
/// </summary>
public class Lich : IHero
{
    /// <summary>
    /// 秀出本身的技能
    /// </summary>
    public void ShowSkills()
    {
        Console.WriteLine("我是巫妖,我会霜冻新星、寒冰甲、黑暗仪式和死亡凋零。");
    }
}
/// <summary>
/// 地穴领主
/// </summary>
public class DL : IHero
{
    /// <summary>
    /// 秀出本身的技能
    /// </summary>
    public void ShowSkills()
    {
        Console.WriteLine("我是地穴领主,我会穿刺、刺盾、腐蚀甲虫和蝗群。");
    }
}
/// <summary>
/// 恐惧魔王
/// </summary>
public class CL : IHero
{
    /// <summary>
    /// 秀出本身的技能
    /// </summary>
    public void ShowSkills()
    {
        Console.WriteLine("我是恐惧魔王,我会腐臭群蜂、睡眠、吸血光环、地狱火。");
    }
}

而后须要修改工厂方法,增长switch语句中的类型,将不死族四个英雄建立逻辑添加进去。对象

/// <summary>
/// 建立英雄的静态方法
/// </summary>
/// <param name="heroName">英雄名称</param>
/// <returns></returns>
public static IHero CreateHero(string hero
{
    switch (heroName)
    {
        //暗夜精灵
         case "DH":
            return new DH();
        case "WD":
            return new WD();
        case "KOG":
            return new KOG();
        case "POM":
            return new POM();
        
        // 不死族
         case "DK":
            return new DK();
        case "Lich":
            return new Lich();
        case "CL":
            return new CL();
        case "DL":
            return new DL();
        default:
            return null;
    }
}

还有兽族及人族,也须要如此修改。到此咱们会感受存在有如下问题blog

一、随着英雄的增多,简单工厂类须要反复修改。

二、简单工厂类过于庞大,职责混乱,负责了四个种族全部英雄的建立,而实际上,玩家在进入游戏时已经选好了本身的种族,只有可能建立所选种族的英雄。

咱们到了这里,首先要想到的是,既然四个种族,分别有本身的祭坛,产生改种族的英雄,咱们应该将简单工厂类按照种族进行职责拆分,此时参考上面提到的工厂方法模式定义以及结构图,咱们会发现,如今是到了工厂方法模式出场的时候了。

1 工厂方法模式详解

一、提炼工厂方法接口

将原来的简单工厂类,进一步提炼为一个工厂方法接口,其包含一个名为CreateHero的接口。

/// <summary>
/// 工厂方法接口
/// </summary>
public interface IFactory
{

    /// <summary>
    /// 建立英雄的方法
    /// </summary>
    /// <param name="heroName">英雄名称</param>
    /// <returns></returns>
    IHero CreateHero(string heroName);
}

二、实现四个种族的工厂方法

四个种族建立英雄的工厂方法继承自工厂方法接口,实现CreateHero。

/// <summary>
/// 暗夜精灵种族英雄工厂类
/// </summary>
public class NEFactory : IFactory
{

    /// <summary>
    /// 建立英雄的静态方法
    /// </summary>
    /// <param name="heroName">英雄名称</param>
    /// <returns></returns>
    public IHero CreateHero(string heroName)
    {
        switch (heroName)
        {
            //暗夜精灵
              case "DH":
                return new DH();
            case "WD":
                return new WD();
            case "KOG":
                return new KOG();
            case "POM":
                return new POM();
            default:
                return null;
        }
    }
}
/// <summary>
/// 不死族英雄工厂类
/// </summary>
public class UDFactory : IFactory
{

    /// <summary>
    /// 建立英雄的静态方法
    /// </summary>
    /// <param name="heroName">英雄名称</param>
    /// <returns></returns>
    public IHero CreateHero(string heroName)
    {
        switch (heroName)
        {

            // 不死族
              case "DK":
                return new DK();
            case "Lich":
                return new Lich();
            case "CL":
                return new CL();
            case "DL":
                return new DL();
            default:
                return null;
        }
    }
}

三、客户端调用

static void Main(string[] args)
{
    IFactory factory = new NEFactory();  // 初始化一个暗夜精灵族的英雄工厂
     Console.WriteLine("我在开局时选择了暗夜精灵族,个人首发英雄是DH。");
    IHero dh = factory.CreateHero("DH");
    dh.ShowSkills();

    factory = new UDFactory();  // 初始化一个不死族的英雄工厂
     Console.WriteLine("我在开局时选择了不死族,个人首发英雄是DK。");
    IHero dk = factory.CreateHero("DK");
    dk.ShowSkills();

    Console.ReadLine();
}

1

四、经过反射实例化具体的工厂方法类

在实际应用中跟上面不一样种族建立英雄的例子相似,通常在系统启动时就已经肯定要使用哪一种方法实例化工厂方法类,一般咱们能够将工厂类的实例化经过配置文件的方式肯定,从而避免源码的修改。

string factoryName = ConfigurationManager.AppSettings["FactoryName"]; // 读取配置文件
IFactory factory = (IFactory)Assembly.Load("FactoryMethodPattern").CreateInstance("FactoryMethodPattern." + factoryName); // 实例化配置的工厂方法类

2 总结

工厂方法模式具备如下优势

一、更容易对现有功能进行扩展,若是有新的需求,只须要实现一个相应的工厂方法实现类便可,无需修改现有代码。

二、不一样工厂方法类,实现了单一职责的设计原则。

工厂方法模式的缺点

因为具体的对象由具体指定的工厂方法类建立,致使具体产品和工厂方法类之间具备较强的耦合性

相关文章
相关标签/搜索