设计模式——工厂模式

工厂模式在我们的项目当中会被频繁使用,这主要是因为他解决了关键字new所引发的类与类之间的依赖。或者说通过工厂能够很好的将类与类解耦。

假设我们是一家手机制造商,好很多品牌的手机都在我们这里下单,进行批量生产制造。其中有Nokia、HTC、Samsung。我要获得一部三星手机。这个程序可以如何写呢?

来看第一个程序。

namespace DesignPattern.Factory

{

   public class Phone

   {

       private string _brand;

       public string Brand

       {

           get { return _brand; }

           set { _brand = value; }

       }

       public override string ToString()

       {

           return string.Format("品牌:{0}",_brand);

       }

   }

}

namespace DesignPattern.Factory

{

   class Program

   {

       static void Main(string[] args)

       {

           Phone myPhone = new Phone();

           myPhone.Brand = "Samsung";

           Console.WriteLine(myPhone.ToString());

       }

   }

}

好吧,这里只有两个角色,一个“电话”,一个“客户”。看起来很别扭。原因就在看起来像客户制造的手机,并且是客户给品牌命名的。并且,如果我动了Phone类的一些东西,那么客户的手机就必须重新制造。好吧,那么咱们重新搞一搞他,引入一个Phone工厂。

首先我们需要把Phone抽象化,使Nokia、HTC、Samsung分别继承它。

   public abstract class Phone

   {

       private string _brand;

       protected void SetBrand(string brand)

       {

           this._brand = brand;

       }

       public override string ToString()

       {

           return string.Format("品牌:{0}",_brand);

       }

   }

   public class NokiaPhone:Phone

   {

       public NokiaPhone()

       {

           this.SetBrand("Nokia");

       }

   }

   public class HTCPhone:Phone

   {

       public HTCPhone()

       {

           this.SetBrand("HTC");

       }

   }

   public class SamsungPhone:Phone

   {

       public SamsungPhone()

       {

           this.SetBrand("Samsung");

       }

   }

我们需要一个工厂,通过一个传入进来的字符串(或者是枚举,推荐枚举)的不同,让其产生不同的Phone对象。

   public class PhoneFactory

   {

       private BrandEnum _brandEnum;

       public PhoneFactory(BrandEnum brandEnum)

       {

           this._brandEnum = brandEnum;

       }

       public Phone CreatePhone()

       {

           Phone phone = null;

           switch (this._brandEnum)

           {

               case BrandEnum.Nokia:

                   phone = new NokiaPhone(); break;

               case BrandEnum.HTC:

                   phone = new HTCPhone(); break;

               case BrandEnum.Samsung:

                   phone = new SamsungPhone(); break;

               default:

                   break;

           }

           return phone;

       }

   }

现在在开看看调用代码。

       static void Main(string[] args)

       {

           Phone myPhone = new PhoneFactory(BrandEnum.Samsung).CreatePhone();

           Console.WriteLine(myPhone.ToString()+

               " 类型:"+myPhone.GetType());

           Console.ReadKey();

       }

好像看起来好多了,让我们来看一下依赖项。

Program只知道我要一个电话,一个三星电话,把这个具体的实例工作交给了PhoneFactory。PhoneFactory根据Programs所提出的要求实例化不同品牌的电话产品,并交给Program。这就是简单工厂,PhoneFactory可以将产品和客户进行解耦。

现在有个问题。PhoneFactory和具体的品牌手机是耦合的,而且相当严重。当我新添加一个手机品牌的时候就必须要修改PhoneFactory。在OO思想中应该尽量避免修改。我们可以将工厂类抽象出去,在下面建立许多小工厂,并且将制造电话的步骤放在小工厂中进行,这样添加一个品牌手机的时候就不用修改PhoneFactory了,而是添加一个SomePhone和一个SomeFactory就可以了。

先来改造一下PhoneFactory,实例化的过程放在小工厂中(因为具体到了小工厂中处理实例化对象,也就是已经知道了产品是什么,所以枚举可以不用判断了,也就是在工厂当中将switch/case剔除掉了),PhoneFactory声明一个抽象方法,让小工厂去实现各自的品牌。

   public abstract class PhoneFactory

   {

       public PhoneFactory()

       {

       }

       public abstract Phone CreatePhone();

   }

诺基亚小工厂,其他依次类推。

   public class NokiaFactory:PhoneFactory

   {

       public override Phone CreatePhone()

       {

           return new NokiaPhone();

       }

   }

。。。。。。

再来得到一部三星手机。

   class Program

   {

       static void Main(string[] args)

       {

           Phone myPhone = new SamsungFactory().CreatePhone();

           Console.WriteLine(myPhone.ToString()+

               " 类型:"+myPhone.GetType());

           Console.ReadKey();

       }

   }

我们再来看一下UML中的依赖关系。

可以看到小工厂以及,品牌电话具有依赖,而其他的都被解耦了,而添加一个品牌电话,则必须伴随一个小工厂,他们是成对出现的,他们的修改不影响其他类。这就是工厂模式。