设计模式-简单工厂模式

一、最开始的代码

  1、种族接口,有一个展示种族英雄的方法

public interface IRace
{
    void ShowKing();
}
        

  2、定义3个种族,实现接口

    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");
        }
    }

  3、定义玩家,玩家可以玩不同种族的英雄

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();
        }       
    }

  4、使用方式

Player player = new Player()
{
     Id = 123,
     Name = "Eleven"
};
Human race = new Human();//1 最原始最习惯的
player.PlayHuman(race);
ORC oRC = new ORC();
player.PlayORC(oRC);

  这种方式,想要使用哪个种族都需要new具体的种族、修改代码来调用不同方法,如果新增了种族,Player类就必须新增新方法PlayNewRace()。这样依赖了细节,不易扩展,需要经常修改代码

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

  换句话说就是:依赖抽象,而不是依赖细节

 

二、依赖抽象

  1、玩家类新增一个方法,该方法可以接收所有的种族,该方法的形参为IRace,可接收实现了IRace接口的类实例。

        public void Play(IRace iRace)
        {
            Console.WriteLine("******************************");
            Console.WriteLine("This is {0} Play War3.{1}", this.Name, iRace.GetType().Name);
            iRace.ShowKing();
        }

  2、使用方式

IRace race = new Human();//2 左边换成抽象 依赖倒置原则
player.Play(race);
IRace race2 = new ORC();
player.Play(race2);

一个方法可以使用所有的种族了。但左边(IRace race = )换成抽象了,右边(new Human();)还是依赖了细节,因为//new IRace();编译不通过,接口不能直接实例化,

那问题出来了,既不想依赖细节,又需要对象,引出工厂。

 

三、简单工厂模式

  1、概念:包含一组需要创建的对象,通过一个工厂类来实例化对象

  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;              default:
                    throw new Exception("wrong raceType");
            }
            return race;
        }
    }
    public enum RaceType
    {
        Human,
        NE,
        ORC
    }

  使用方式

IRace race = ObjectFactory.CreateInstance(RaceType.Human);
player.Play(race);

  但是如果现在要换成使用ORC种族,则又要修改代码,变成

IRace race = ObjectFactory.CreateInstance(RaceType.ORC);
player.Play(race);

  下面使用配置文件的方法,来传入要使用的种族

 

  3、使用配置文件配合简单工厂模式

  配置文件App.config新增配置项节点  

<appSettings>
    <add key="IRaceType" value="Human"/>
  </appSettings>

  ObjectFactory工厂类新增方法

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);

  这样如果要改变使用的种族,就不必要修改代码了,直接修改配置文件的IRaceType的value值。

  但如果现在要新增一个新种族Undead不死族,首先新增Undead类

namespace FactoryPattern.War3.Service
{
    /// <summary>
    /// War3种族之一
    /// </summary>
    public class Undead : IRace
    {
        public void ShowKing()
        {
            Console.WriteLine("The King of {0} is {1}", this.GetType().Name, "GoStop");
        }
    }
}

 

  然后还需要修改代码,RaceType枚举新增Undead

public enum RaceType
    {
        Human,
        NE,
        ORC,
        Undead
    }

 

  undead可以通过类库引入,不用修改现有代码,但是还是要修改修改RaceType枚举。

 

  现在再升级为通过反射来创建种族实例,这样就可以不用修改RaceType枚举了

 

  4、使用反射配合简单工厂模式

  配置文件App.config新增配置项节点

<appSettings>
    <add key="IRaceTypeReflection" value="FactoryPattern.War3.Service.Undead,FactoryPattern.War3.Service"/>
  </appSettings>

  ObjectFactory工厂类新增方法

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);
        }

 

  这样以后只要修改app.config里的配置项,上端就能不修改代码也可以使用不同种族了,还支持新增种族。

 

四、问题

今天只是创建Race,就需要一个方法;那项目中有N多个接口,难道每个接口都去创建一个工厂方法吗?

简单工厂模式还不能支持,需要抽象工厂模式,或者ioc容器

 

posted @ 2022-03-27 17:08  暗,伏!  阅读(26)  评论(0编辑  收藏  举报