从简单工厂模式我们可以看出,在简单工厂模式中,增加新的产品类,是需要修改工厂类的,这不符合开放-封闭原则.而且在写工厂类的时候必须知道具体产品类的细节.也不符合由上相下的设计原则,如果要延后关注细节,则必须利用继承或者接口的技术来实现.将简单工厂模式中的工厂抽象,增加抽象工厂角色,这样用户,抽象工厂,抽象产品,用户就形成了最顶层的设计层面,具体的实现由具体的工厂来创建具体的产品.着就是工厂方法模式.
工厂方法模式角色:用户,抽象工厂,抽象产品,具体工厂,具体产品.
工厂方法模式采用一个具体工厂生产一种具体产品的方式进行产品的创建.用户具体要创建那种产品的选择逻辑推给了用户,用户通过选择不同的具体工厂来实现不同产品的创建选择.
工厂方法的优点:
1.符合开放封闭原则,因为增加新的产品不需要修改原来已有的工厂类,只需要增加相应的工厂即可.
2.将使用和创建的责任分开.
3.符合设计的先抽象后具体的顺序.
缺点:
1.如果产品类太多会导致增加很多的类,会使系统显得很不简洁.
2.如果将选择逻辑交给用户,则在一定程度上增加了用户对细节的依赖;
3.与简单工厂模式相比,增加了工厂本身的创建开销.
4.用户需要创建工厂类本身.(通过一定的方法可以将工厂类的创建委托给抽象类去完成.见例子.
抽象工厂方法是工厂方法更一般的表达,工厂方法可以针对产品族(如控件的Windows族控件,Unix族控件),如果只有一族产品(比如只有Windows族)则就退化成简单工厂方法(如果除掉抽象工厂,将工厂方法变为静态的方法,利用参数化减少工厂方法数量为1个,则就是简单工厂方法).)(一个工厂类,每个工厂方法创建一种产品).而如果只有一类产品(如只有Button控件),则退化成标准的工厂方法类似
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//变形的工厂方法
namespace MyBaseStudy
{
abstract class AbstractFactory
{
//这种方法也需用户创建工厂类。
public static AbstractProduct CreateProductM1(AbstractFactory bb)
{
return bb.CreateAProduct();
}
//利用模板方法将工厂类的创建委托给抽象工厂本身。
public static AbstractProduct CreateProductM2<T>() where T : AbstractFactory,new()
{
T factory = new T();
return factory.CreateAProduct();
}
public abstract AbstractProduct CreateAProduct();
}
abstract class AbstractProduct
{
public abstract double GetPrice();
public abstract void AddPrice(double p);
}
class ConcreteFactoryA : AbstractFactory
{
public override AbstractProduct CreateAProduct()
{
return new ConcreteProductA(100);
}
}
class ConcreteFactoryB : AbstractFactory
{
public override AbstractProduct CreateAProduct()
{
return new ConcreteProductB(200,0.9);
}
}
class ConcreteProductA : AbstractProduct
{
double _price;
public ConcreteProductA(double price)
{
this._price = price;
}
public override double GetPrice()
{
return this._price;
}
public override void AddPrice(double p)
{
this._price += p + 1;
}
}
class ConcreteProductB : AbstractProduct
{
double _price;
double _rate;
public ConcreteProductB(double price,double rate)
{
this._price = price;
this._rate = rate;
}
public override double GetPrice()
{
return this._price;
}
public override void AddPrice(double p)
{
this._price += p * this._rate;
}
}
class Client
{
public static void Test()
{
//方法1,一般的使用方法,用户需要自己创建工厂类,要创建产品A
AbstractFactory fa2 = new ConcreteFactoryA();
AbstractProduct pa2 = fa2.CreateAProduct();
System.Windows.Forms.MessageBox.Show(pa2.GetPrice().ToString());
//方法2,一般的使用方法,用户需要自己创建工厂类,要创建产品A,这种方法跟1比没什么优势,
//只是如果将CreateAProduct弄成保护类型,则可以隐藏创建细节,同时也可以起到一定代理模式的作用
AbstractFactory fa1 = new ConcreteFactoryA();
AbstractProduct pa1 = AbstractFactory.CreateProductM1(fa1);
System.Windows.Forms.MessageBox.Show(pa1.GetPrice().ToString());
//方法3,使用泛型方法方法,用户不需要自己创建工厂类,创建产品B,但这种方法的局限是工厂类必须具有不需要参数化的构造函数。
AbstractProduct pb = AbstractFactory.CreateProductM2<ConcreteFactoryB>();
System.Windows.Forms.MessageBox.Show(pb.GetPrice().ToString());
}
}
}
工厂方法和简单工厂一样,如果产品类太多都会导致具体的工厂类或方法过多,改进的办法是利用泛型,当然也可以利用反射,而且利用反射还可以进行参数化构造,但不利的地方是这同样会导致用户对构造细节的依赖.hibernate的构造方式其实就是这种方式,他将用户对构造细节的依赖转换成了可以动态配置的文件形式,而不是直接依赖.采用这种方式还有的好处就是工厂可以创造多种产品.但这种方式的一个缺点是需要采用动态参数构造目标产品的时候,这种方式就很难办到了.