连续几天没有写博客了,之前计划每天温习一个设计模式的,但是计划不如变化,现在看来是不可能的了,工作还是很重要的,做不完的话生活就没有保障了。
今天看了工厂方法模式,发现工厂方法模式跟简单工厂模式的差异还是很大的,简单工厂模式的核心是有一个具体的工厂类来产生具体对象而工厂方法的核心是一个抽象工厂,这个抽象工厂可以是一个接口或者抽象类,
工厂方法模式还有一个别名叫多态性工厂模式,是因为具体工厂类都有共同的接口,或者有共同的抽象父类。
工厂模式的缺点是如果系统需要加入一个新的产品,就需要修改静态工厂,以便能够返回新的产品,也就是说当产品类有复杂的多层次等级结构时,工厂类只有它自己,以不变应万变,这个是简单工厂模式的缺点,还有一个是,当产品有不同的接口种类时,工厂类需要判断在什么时候创建某种产品,当系统足够复杂时,对于后续程序的扩展就比较困难了。
工厂方法模式刚好可以解决简单工厂模式的上述问题:当系统需要加入一个新的产品的时候,那么需要做的也就是向系统中加入一个这个产品类以及产品对应的工厂类。没有必要修改客户端,也没有必要修改抽象工厂角色或者其他已有的具体产品角色。对于新增加的产品类而言,这个系统完全支持“开---闭”原则。
我们以经典的水果庄园为例子来看看在工厂方法模式中,水果庄园是如何实现的。
以前水果庄园规模很小,一个农夫就可以忙过来了,这个农夫可以同时负责种植苹果,葡萄,草莓,但是随着庄园的不断壮大水果庄园也发展为一个规模空前的农场,很显然一位农夫是不可能管理这个农场的。这个时候我们就需要扩招农夫来分类管理农场了,虽说每个农夫管理的作物范围不同,但是他们的职责却是类似的,种植,收获,除草等等,下面我们通过系统结构图来看看这个农场的职责。
通过类结构图我们可以看到,FruitGardener是这个农场的核心类,即工厂方法的核心,但是它并没有掌握具体某一类作物的生杀大权,它只是定义了作为Gardener的一系列职责,而职责的具体执行者,就落实到了负责管理具体作物的Gardener身上。接下来我们来看看园丁具体代码是如何实现的。
public interface FruitGardener
{
Fruit Factory();
}
public class AppleGardener : FruitGardener
{
public Fruit Factory()
{
return new Apple();
}
}
public class GrapeGardener : FruitGardener
{
public Fruit Factory()
{
return new Grape();
}
}
public class StrawberryGardener:FruitGardener
{
public Fruit Factory()
{
return new StrawBerry();
}
}
可以看得出,具体的园丁类都继承自接口FruitGardener,这样他们各自也就实现了接口中的Factory,要求返回一个Fruit类型的对象,我们再来看看Fruit的代码层次结构:
public interface Fruit
{
void Grow();
void Harvest();
void Plant();
}
public class Apple : Fruit
{
public void Grow()
{
Console.WriteLine("Apple is growing..........");
}
public void Harvest()
{
Console.WriteLine("Apple has been harvested.............");
}
public void Plant()
{
Console.WriteLine("Apple hse been planted.............");
}
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
}
public class Grape : Fruit
{
public void Grow()
{
Console.WriteLine("Grape is growing..........");
}
public void Harvest()
{
Console.WriteLine("Grape has been harvested.............");
}
public void Plant()
{
Console.WriteLine("Grape hse been planted.............");
}
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
private bool seedless;
public bool Seedless
{
get { return seedless; }
set { seedless = value; }
}
}
public class StrawBerry:Fruit
{
public void Grow()
{
Console.WriteLine("StrawBerry is growing..........");
}
public void Harvest()
{
Console.WriteLine("StrawBerry has been harvested.............");
}
public void Plant()
{
Console.WriteLine("StrawBerry hse been planted.............");
}
private int age;
public int Age
{
get { return age; }
set { age = value; }
}
}
可以看出,所有的作物类都实现了Fruit这个接口,也就是说所有的作物都要经历种植,生长,收获,为什么Age没有放到接口中呢?因为不是所有的Fruit都是多年生的,恰巧我们描述的这三种作物都是多年生的,假如说在种植一个番茄,那这个Age几乎就没用了。
农场管理者需要做的事情:招工,分配作物管理,指导工作,而自己无需要亲自去管理作物。
public class GardenManager
{
FruitGardener appleGardener, grapeGardener, StrawberryGardener;
Fruit apple, grape, strawberry;
public void ManageGardener()
{
appleGardener = new AppleGardener();
grapeGardener = new GrapeGardener();
StrawberryGardener = new StrawberryGardener();
apple = appleGardener.Factory();
grape = grapeGardener.Factory();
strawberry = StrawberryGardener.Factory();
apple.Plant();
apple.Grow();
apple.Harvest();
grape.Plant();
grape.Grow();
grape.Harvest();
strawberry.Plant();
strawberry.Grow();
strawberry.Harvest();
}
}
值得注意的地方:
假如我们创建的工厂方法中有共同的逻辑,那么我们需要把这些共同的逻辑抽象到上一层,多个工厂中的相同逻辑应该移至超类中,剩下的就是自己在实际的项目经验中如何去使用工厂方法解决问题了。
上述例子运行结果如下: