【设计模式-手写源码-附1】-简单工厂模式-基于魔兽争霸冰封王座

1:主题拆解

①依赖倒置原则-SimpleFactory

②简单工厂+ 配置文件=可配置

③简单工厂+ 配置文件+反射=可配置可扩展

④简单工厂升级IOC控制反转

2:基本介绍

①学习设计模式的套路:场景出发-->解决问题-->沉淀总结-->推广应用(无尽升级)

②需要指出GOF23种设计模式是不包含简单工厂,因此上面写的是 附1

③一句话描述:简单工厂设计模式包含一组需要创建的对象,通过一个工厂类来实例化对象

④依赖倒置原则:上层模块不应该依赖于下层模块,二者应该通过抽象来依赖

依赖抽象,而不是依赖细节。

3:场景介绍

我们以魔兽争霸冰封王座的游戏背景来解析当前的设计模式。

①定义了4个种族,依次为Human,NE,ORC,Undead

 public class Human : IRace
    {
        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Sky");
        }
    }

public class NE : IRace
    {
        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Moon");
        }
    }

    public class ORC : IRace
    {
        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Grubby");
        }
    }

 public class Undead : IRace
    {
        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "GoStop");
        }
    }

②定义了一个接口,包括ShowKing方法。给上面四个种族继承

public interface IRace

    {

        void ShowKing();

    }

③定义一个玩家类Player,包含方法4个方法PlayHuman,PlayNE,PlayORC,PlayUndead

public class Player
    {
        public int Id { get; set; }
        public string Name { get; set; }


        public void PlayHuman(Human human)
        {
            Console.WriteLine("******************************");
            Console.WriteLine("This is {0} Play War3.{1}", this.Name, human.GetType().Name);
            human.ShowKing();
        }
        public void PlayNE(NE ne)
        {
            Console.WriteLine("******************************");
            Console.WriteLine("This is {0} Play War3.{1}", this.Name, ne.GetType().Name);
            ne.ShowKing();
        }
        public void PlayORC(ORC orc)
        {
            Console.WriteLine("******************************");
            Console.WriteLine("This is {0} Play War3.{1}", this.Name, orc.GetType().Name);
            orc.ShowKing();
        }
        public void PlayUndead(Undead undead)
        {
            Console.WriteLine("******************************");
            Console.WriteLine("This is {0} Play War3.{1}", this.Name, undead.GetType().Name);
            undead.ShowKing();
        }
    }

④基于上面3步完成之后,玩家就可以开始进行War3游戏了。

例如玩家Micro,依次开始玩遍四个种族,实现的代码如下

Player player = new Player()
{
    Id = 666,
    Name = "Micro"
};
{
    Human human = new Human();
    player.PlayHuman(human);
    NE ne = new NE();
    player.PlayNE(ne);
    ORC orc = new ORC();
    player.PlayORC(orc);
    Undead undead = new Undead();
    player.PlayUndead(undead);
}

4:解决问题

从上层模块的调用可以看出,每次调用一个种族都需要对下端的细节形成了依赖。

根据设计模式依赖导致原则,该方式的代码得要做升级。

升级1

Player添加方法,用面向接口,面向抽象的方式实现

public void Play(IRace iRace)
        {
            Console.WriteLine("******************************");
            Console.WriteLine("This is {0} Play War3.{1}", this.Name, iRace.GetType().Name);
            iRace.ShowKing();
        }
    IRace human = new Human();                
    IRace ne = new NE();              
    IRace orc = new ORC();     
    IRace undead = new Undead();
    player.Play(human);
    player.Play(ne);
    player.Play(orc);
    player.Play(undead);

分析:左边换成抽象,依赖倒置原则,采用接口的方式。但是我们发现右边照样也是依赖的细节

 升级2

添加一个工厂类,用于解决四个种族的创建

    public class ObjectFactory
    {
        public static IRace CreateInstance(RaceType raceType)
        {
            IRace race = null;
            switch (raceType)
            {
                case RaceType.Human:
                    race = new Human();
                    break;
                case RaceType.NE:
                    race = new NE();
                    break;
                case RaceType.ORC:
                    race = new ORC();
                    break;
                case RaceType.Undead:
                    race = new Undead();
                    break;
                default:
                    throw new Exception("wrong raceType");
            }
            return race;
        }
    }
public enum RaceType
    {
        Human,
        NE,
        ORC,
        Undead
    }

    IRace human = ObjectFactory.CreateInstance(RaceType.Human);
    IRace ne = ObjectFactory.CreateInstance(RaceType.NE);
    IRace orc = ObjectFactory.CreateInstance(RaceType.ORC);
    IRace undead = ObjectFactory.CreateInstance(RaceType.Undead);
    player.Play(human);
    player.Play(ne);
    player.Play(orc);
    player.Play(undead);

分析:到此为此,简单工厂的模式就已经结束了。

5:简单工厂优缺点

优点

①使用到了依赖倒置原则,上层模块不应该依赖于下层模块,二者应该通过抽象来依赖

依赖抽象,而不是依赖细节。

②去掉上端对细节的依赖,保证上端的稳定。

③上端不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。

缺点

①没有消除矛盾,只是转移矛盾,甚至还集中了矛盾。

②由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中,职责过重,一旦异常,整个系统将受影响。

③它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。

④简单工厂模式使用了static工厂方法,造成工厂角色无法形成基于继承的等级结构

6:可配置版升级

通过配置文件的方式实现初始化不同的工厂实例

①配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="IRaceType" value="Human"/>   
  </appSettings>
</configuration>

②工厂类中添加通过配置文件的方式指定实例化对象

 private static string IRaceType = ConfigurationManager.AppSettings["IRaceType"];
        public static IRace CreateInstanceConfig()
        {
            RaceType raceType = (RaceType)Enum.Parse(typeof(RaceType), IRaceType);
            return CreateInstance(raceType);
        }

③上端调用

 IRace race = ObjectFactory.CreateInstanceConfig();
 player.Play(race);

分析:到此为此,我们就可以在不改动任何源码的情况下,只通过修改配置文件中的值就能实现类的实例化

7:可配置可扩展升级版

真正的把细节依赖给去掉,意味着不能直接new,那怎么获取对象? 于是可以想到反射

①配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="IRaceTypeReflection" value="FactoryPattern.War3.Service.Human,FactoryPattern.War3.Service"/>
  </appSettings>
</configuration>

②工厂类是反射的实现方法

private static string IRaceTypeReflection = ConfigurationManager.AppSettings["IRaceTypeReflection"];
public static IRace CreateInstanceConfigReflection()
{
    Assembly assembly = Assembly.Load(IRaceTypeReflection.Split(',')[1]);
    Type type = assembly.GetType(IRaceTypeReflection.Split(',')[0]);
    return (IRace)Activator.CreateInstance(type);
}

③上端调用

IRace race = ObjectFactory.CreateInstanceConfigReflection();
player.Play(race);

分析:此时我们就已经实现了,通过配置文件+简单工厂+反射实现完全面向抽象的方式调用。

8:如何扩展

对于上面可配置可以扩展,扩展点在哪里?如何扩展?

假如War3升级新增加了第5种族,该如何实现?

咱也不废话,直接上源码

①新建项目,添加第5种族类,继承自IRace

public class Five : IRace
{
    public void ShowKing()
    {
        Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "Alex");
    }
}

②配置文件设置成第5种族

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <add key="IRaceTypeReflection" value="FactoryPattern.War3.ServiceExtend.Five,FactoryPattern.War3.ServiceExtend"/>
  </appSettings>
</configuration>

③上端调用部分不变

IRace race = ObjectFactory.CreateInstanceConfigReflection();
player.Play(race);

分析:此时我们发现在不更改原代码的情况下,只需额外添加新的第5种族,就可以实现对第5种族的扩展。

9:简单工厂升级IOC控制反转

①相信我们发现任何设计模式都是解决一类问题的,不是万能的,通常在解决一类问题的时候,还会带来新的问题。

②我们可以不停的采用技术手段扬长避短,对程序不停的进行升级,相信在不断升级的过程中,我们自己对知识的综合利用能力的总结。

③拆解到此处,我们其实也明白了系统框架中的IOC控制反转,依赖倒置等等无非就是设计模式进行升级的产品。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不要迷恋发哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值