第十二章 简单工厂模式
首先给出简单工厂模式的一个示意图:
简单工厂模式就是由一个工厂类根据传入的参量决定创建出哪一种产品类的实例。
对于多层次的产品结构如下:
图中从Factory类到各个Product类的虚线代表创建(依赖)关系;从Client到其他类的连线是一般依赖关系。
这样做的好处是设计简单,产品类的等级结构不会反映到工厂类中来,从而产品类的等级结构的变化也就不会影响到工厂类。但是这样做的缺点是,增加新的产品必将导致工厂类的修改。
使用java接口或者java抽象类
如果模式所产生的具体产品类彼此之间没有共同的商业逻辑,那么抽象产品角色可以由一个java接口扮演,相反,如果这些具体产品类彼此之间确实有共同的商业逻辑,那么这些共有的逻辑就应该移到抽象角色里面,这就意味着抽象角色应当由一个抽象类扮演。在一个类型的等级结构里面,共同的代码应当尽量向上移动,已达到共享的目的。
简单工厂模式的缺点
当产品类有不同的接口种类时,工厂类需要判断在什么时候创建某种产品。这种对时机的判断和对哪一种具体产品的判断逻辑混合在一起,使得系统在将来进行功能扩展时较为困难。这一缺点在工厂方法模式中得到克服
开闭原则
在这个系统中,功能的扩展体现在引进新的产品上。开闭原则要求系统允许当新的产品加入系统中时,而无需对现有代码进行修改。这一点对于产品的消费角色是成立的,而对于工厂角色是不成立的。。(在增加一个产品类的时候,需要修改工厂类,这不符合开闭原则)
简单工厂代码:
产品:水果,葡萄,草莓,苹果。
水果接口:
public interface Fruit {
void harvest();
void plant();
}
苹果:
public class Apple implements Fruit {
private int treeAge;
public void grow() {
log("Apple is growing..");
}
public void harvest() {
log("Apple has been harvested..");
}
public void plant() {
log("Apple has been planted..");
}
public static void log(String msg) {
System.out.println(msg);
}
public int getTreeAge() {
return treeAge;
}
public void setTreeAge(int treeAge) {
this.treeAge = treeAge;
}
}
葡萄和草莓和苹果代码几乎一样在这里就不重复了。
园丁类的代码如下(工厂)
public class FruitGardener {
public static Fruit factory(String which)
throw BadFruitException {
if(which.equalsIgnoreCase("apple")) {
return new Apple();
} else if(which.equalsIgnoreCase("strawberry")) {
return new strawberry();
} else if(which.equalsIgnoreCase("grape")) {
return new Grape();
} else {
throw new BadFruitException("BadFruitException");
}
}
}
自我感觉简单工厂模式就是使用which这种生产产品,不存在等级结构。
第十三章 工厂方法
工厂方法模式是类的创建模式,又叫做虚拟构造子模式或者多态工厂模式。
工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
同简单工厂模式,在这里给出一个工厂方法的示意图:
源码将在最后给出。
工厂方法模式和简单工厂模式
工厂方法模式和简单工厂模式在结构上的不同时很明显的。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
与简单工厂模式中的情形一样的是,ConcreteCreator的Factory方法返还的数据类型是一个抽象类型Product,而不是哪一个具体的产品类型,而客户端也不必知道所得到的产品的真实类型。这种多态性设计将工厂类选择哪一个产品对象、如何创建这个对象的细节完全封装在具体工厂类内部。
工厂方法模式之所以有一个别名叫做多态性工厂模式,显然是因为具体工厂类都有一个共同的接口,或者都有共同的抽象父类。
如果系统需要加入一个新的产品,那么所需要的就是向系统中加入一个这个产品类以及它所对应的工厂类。没有必要修改客户端,也没有必要修改抽象工厂角色或者其他已有的具体工厂角色。对于增加新的产品类而言,这个系统完全支持开闭原则。
下面是一个工厂方法在农场系统中的实现图:
java语言中工厂方法模式的例子
URL与URLConnection的应用:
package com.javapatterns.factorymethod.url;
import java.net.*;
import java.io.*;
public class URLConnectionReader
{
public static void main(String[] args) throws Exception
{
URL yahoo = new URL("http://www.yahoo.com/");
URLConnection yc = yahoo.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
运行时的活动顺序如下:
1.创建一个以http://www.yahoo.com为目标的url对象。
2.调用url对象的openConnection方法,得到一个http://www.yahoo.com的远程连接对象,这个对象的类型是URLConnection。
3.客户端调用URLConnection对象的getInputStream方法读入远程URL的数据。
这个系统在运行时会打印出http://www.yahoo.com主页的全部HTML源代码。
下面是工厂方法的代码:
产品接口:
package com.javapatterns.factorymethod;
public interface Product
{
}
产品1和产品2:
package com.javapatterns.factorymethod;
public class ConcreteProduct1 implements Product
{
public ConcreteProduct1()
{
System.out.println("CocnreteProduct1 is being created.");
}
}
package com.javapatterns.factorymethod;
public class ConcreteProduct2 implements Product
{
public ConcreteProduct2()
{
System.out.println("CocnreteProduct2 is being created.");
}
}
抽象生产者:
package com.javapatterns.factorymethod;
public interface Creator
{
public Product factory();
/** @link dependency
* @label Creates*/
/*# Product lnkProduct; */
}
两个具体的生产者(ConcreteCreator1 ConcreteCreator2):
package com.javapatterns.factorymethod;
public class ConcreteCreator1 implements Creator
{
public Product factory()
{
return new ConcreteProduct1();
}
}
package com.javapatterns.factorymethod;
public class ConcreteCreator2 implements Creator
{
public Product factory()
{
return new ConcreteProduct2();
}
}
客户端:
package com.javapatterns.factorymethod;
public class Client
{
private static Creator creator1, creator2;
private static Product prod1, prod2;
public static void main(String[] args)
{
creator1 = new ConcreteCreator1();
prod1 = creator1.factory();
creator2 = new ConcreteCreator2();
prod2 = creator2.factory();
}
}
个人感觉工厂方法就是建立和产品一样的等级结构。
第十四章 抽象工厂模式
首先给出抽象工厂模式的简略类图:
左边的等级结构代表工厂等级结构,右边的两个等级结构分别代表两个不同的产品的等级结构。
在什么情况下应当使用抽象的工厂模式
1.一个系统不应该依赖与产品类实例如何被创建,组合和表达的细节,这对于所有形态的工厂模式都是重要的。
2.这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品
3.同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
4.系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
增加新的产品等级结构
在产品族的数目不变的情况下,增加新的产品等级结构。换言之,所有的产品等级结构中的产品数目不会改变,但是现在多出一个与现有的产品等级结构平行的新的产品等级结构。
要做到这一点,就需要修改所有的工厂角色,给每一个工厂类都增加一个新的工厂方法,而这显然是违背开闭原则的。换言之,对于产品等级结构的增加,抽象工厂模式是不支持开闭原则的。
综合起来,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,而不能为新的产品等级结构的增加提供这样的方便。
抽象工厂模式在农场系统中的实现
蔬菜总接口:
package com.javapatterns.abstractfactory.farm;
public interface Veggie
{
}
北方和热带蔬菜:
package com.javapatterns.abstractfactory.farm;
public class NorthernVeggie implements Veggie
{
private String name;
public NorthernVeggie(String name)
{
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
package com.javapatterns.abstractfactory.farm;
public class TropicalVeggie implements Veggie
{
private String name;
public TropicalVeggie(String name)
{
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
水果:
package com.javapatterns.abstractfactory.farm;
public interface Fruit
{
}
北方和热带水果:
package com.javapatterns.abstractfactory.farm;
public class NorthernFruit implements Fruit
{
private String name;
public NorthernFruit(String name)
{
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
package com.javapatterns.abstractfactory.farm;
public class TropicalFruit implements Fruit
{
private String name;
public TropicalFruit(String name)
{
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
园丁接口:
package com.javapatterns.abstractfactory.farm;
public interface Gardener
{
public Fruit createFruit(String name);
public Veggie createVeggie(String name);
}
北方和热带园丁:
package com.javapatterns.abstractfactory.farm;
public class NorthernGardener implements Gardener
{
public Fruit createFruit(String name)
{
return new NorthernFruit(name);
}
public Veggie createVeggie(String name)
{
return new NorthernVeggie(name);
}
}
package com.javapatterns.abstractfactory.farm;
public class TropicalGardener implements Gardener
{
public Fruit createFruit(String name)
{
return new TropicalFruit(name);
}
public Veggie createVeggie(String name)
{
return new TropicalVeggie(name);
}
}
上面代码的设计图如下:
个人理解抽象工厂模式就是对于多个产品族的。这多个产品族的结构相同,生产者的等级结构的每一部分对应生产产品族的一个部分。