工厂模式分为三类:
Ø 简单工厂模式(Simple Factory)
Ø 工厂方法模式(Factory Method)
Ø 抽象工厂模式(Abstract Factory)
这三种模式从上到下逐步抽象,并且更具一般性。
简单工厂模式
简单工厂模式又称静态工厂方法模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
该模式中包含的角色及其职责
Ø 工厂类角色:这是本模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
Ø 抽象产品角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
Ø 具体产品角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
优缺点
优点
工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象.通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面摆脱出来,仅仅需要负责“消费”对象就可以了。而不必管这些对象究竟如何创建及如何组织的.明确了各自的职责和权利,有利于整个软件体系结构的优化。
缺点
由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。
当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求.这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。这些缺点在工厂方法模式中得到了一定的克服。
使用场景
Ø 工厂类负责创建的对象比较少;
Ø 客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;
Ø 由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。
简单工厂模式的一个小例子
// 在这里,我们先定义水果(Fruit)接口:
public interface Fruit {
void plant(); // 水果是被种植的
void enableEat(); // 水果能吃
}
// 苹果(Apple)是对水果(Fruit)接口的实现:
public class Apple implements Fruit {
public void plant() {
System.out.println("种苹果!");
}
public void enableEat() {
System.out.println("苹果好吃!");
}
}
// 葡萄(Grape)是对水果(Fruit)接口的实现:
public class Grape implements Fruit {
public void plant() {
System.out.println("种葡萄!");
}
public void enableEat() {
System.out.println("葡萄好吃!");
}
}
// 鸭梨(Pear)是对水果(Fruit)接口的实现:
public class Pear implements Fruit {
public void plant() {
System.out.println("种鸭梨!");
}
public void enableEat() {
System.out.println("鸭梨好吃!");
}
// 定义买水果(BuyFruit)这一过程类:
public class BuyFruit {
public static Fruit buyFruit(String which) {
if (which.equalsIgnoreCase("apple")) { // 如果是苹果,则返回苹果实例
return new Apple();
} else if (which.equalsIgnoreCase("pear")) { // 如果是鸭梨,则返回鸭梨实例
return new Pear();
} else if (which.equalsIgnoreCase("grape")) { // 如果是葡萄,则返回葡萄实例
return new Grape();
} else {
return null;
}
}
// 编写测试类:
public class FruitTest {
public static void main(String args[]) {
BuyFruit buy = new BuyFruit(); // 开始买水果这个过程
buy.buyFruit("apple").enableEat(); // 调用苹果的enableEat()方法
}
}
说明:
Ø 我要购买苹果,只需向工厂角色(BuyFruit)请求即可。而工厂角色在接到请求后,会自行判断创建和提供哪一个产品。
Ø 但是对于工厂角色(BuyFruit)来说,增加新的产品(比如说增加草莓)就是一个痛苦的过程。工厂角色必须知道如何创建每一种产品,以及何时向客户端提供它们。换言之,接纳新的产品意味着修改这个工厂。
Ø 因此简单工厂模式的开放性比较差。
工厂方法模式
工厂方法(Factory Method)模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先完全实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,可以应用于产品结果复杂的场合。
工厂方法模式是对简单工厂模式进行了抽象。有一个抽象的Factory类(可以是抽象类和接口),这个类将不在负责具体的产品生产,而是只制定一些规范,具体的生产工作由其子类去完成。在这个模式中,工厂类和产品类往往可以依次对应。即一个抽象工厂对应一个抽象产品,一个具体工厂对应一个具体产品,这个具体的工厂就负责生产对应的产品。
工厂方法模式(Factory Method pattern)是最典型的模板方法模式(Templete Method pattern)应用。
该模式中包含的角色及其职责
Ø 抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
Ø 具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。
Ø 抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。
Ø 具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
优缺点
使用场景
Ø 对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。Java Collection中的iterator() 方法即属于这种情况。
Ø 只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。
工厂方法模式的一个小例子
// 同样,我们先定义水果(Fruit)接口:
public interface Fruit {
void plant(); // 水果是被种植的
void enableEat(); // 水果能吃
}
// 苹果(Apple)是对水果(Fruit)接口的实现:
public class Apple implements Fruit {
public void plant() {
System.out.println("种苹果!");
}
public void enableEat() {
System.out.println("苹果好吃!");
}
}
// 葡萄(Grape)是对水果(Fruit)接口的实现:
public class Grape implements Fruit {
public void plant() {
System.out.println("种葡萄!");
}
public void enableEat() {
System.out.println("葡萄好吃!");
}
}
// 鸭梨(Pear)是对水果(Fruit)接口的实现:
public class Pear implements Fruit {
public void plant() {
System.out.println("种鸭梨!");
}
public void enableEat() {
System.out.println("鸭梨好吃!");
}
}
// 在这里我们将买水果(BuyFruit)定义为接口类:
public interface BuyFruit {
public Fruit buyFruit(); // 定义买水果这一过程
}
// 买苹果是(BuyApple)对买水果(BuyFruit)这个接口的实现
public class BuyApple implements BuyFruit {
public Fruit buyFruit() {
return new Apple(); // 返回苹果实例
}
}
// 买鸭梨是(BuyPear)对买水果(BuyFruit)这个接口的实现
public class BuyPear implements BuyFruit {
public Fruit buyFruit() {
return new Pear(); // 返回鸭梨实例
}
}
// 买葡萄是(BuyGrape)对买水果(BuyFruit)这个接口的实现
public class BuyGrape implements BuyFruit {
public Fruit buyFruit() {
return new Grape(); // 返回葡萄实例
}
}
// 编写测试类:
public class FruitTest {
public static void main(String args[]) {
BuyFruit buy = new BuyApple(); // 开始买水果这个过程
buy.buyFruit().enableEat(); // 调用苹果的enableEat()方法
}
}
说明:
Ø 工厂方法模式和简单工厂模式在结构上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。工厂方法模式可以允许很多具体工厂类从抽象工厂类中将创建行为继承下来,从而可以成为多个简单工厂模式的综合,进而推广了简单工厂模式。
Ø 工厂方法模式退化后可以变得很像简单工厂模式。设想如果非常确定一个系统只需要一个具体工厂类,那么就不妨把抽象工厂类合并到具体的工厂类中去。由于反正只有一个具体工厂类,所以不妨将工厂方法改成为静态方法,这时候就得到了简单工厂模式。
Ø 如果需要加入一个新的水果,那么只需要加入一个新的水果类以及它所对应的工厂类。没有必要修改客户端,也没有必要修改抽象工厂角色或者其他已有的具体工厂角色。对于增加新的水果类而言,这个系统完全支持"开-闭"原则。
Ø 对工厂方法模式而言,它只是针对一种类别(如本例中的水果类Fruit),但如果我们还想买肉,那就不行了,这是就必须要抽象工厂模式帮忙了。
抽象工厂模式
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体的情况下,创建多个产品族中的产品对象。根据LSP原则,任何接受父类型的地方,都应当能够接受子类型。因此,实际上系统所需要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责创建抽象产品的具体子类的实例。工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构。
该模式中包含的角色及其职责
Ø 抽象工厂角色(Creator): 抽象工厂模式的核心,包含对多个产品结构的声明,任何工厂类都必须实现这个接口。
Ø 具体工厂角色(Concrete Creator):具体工厂类是抽象工厂类的一个实现,负责实例化某个产品族的产品对象。
Ø 抽象角色(product):抽象模式所创建的所有对象的父类,它描述所有实例所共有的公共接口。
Ø 具体产品角色(Concfrete Product):抽象模式岁创建的具体实例对象
优缺点
优点
分离接口和实现,客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦。
使切换产品族变得容易,因为一个具体的工厂实现代表的是一个产品族。
缺点
不太容易扩展新的产品,如果需要给整个产品族添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。
使用场景
Ø 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
Ø 这个系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。
Ø 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
Ø 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
抽象工厂模式的一个小例子
// 同样,我们先定义水果(Fruit)接口:
public interface Fruit {
void plant(); // 水果是被种植的
void enableEat(); // 水果能吃
}
// 苹果(Apple)是对水果(Fruit)接口的实现:
public class Apple implements Fruit {
public void plant() {
System.out.println("种苹果!");
}
public void enableEat() {
System.out.println("苹果好吃!");
}
}
// 葡萄(Grape)是对水果(Fruit)接口的实现:
public class Grape implements Fruit {
public void plant() {
System.out.println("种葡萄!");
}
public void enableEat() {
System.out.println("葡萄好吃!");
}
}
// 鸭梨(Pear)是对水果(Fruit)接口的实现:
public class Pear implements Fruit {
public void plant() {
System.out.println("种鸭梨!");
}
public void enableEat() {
System.out.println("鸭梨好吃!");
}
}
// 定义肉(Meat)接口:
public interface Meat {
void feed(); // 肉是喂养的
void enableEat(); // 肉能吃
}
// 猪肉(PigMeat)是对肉(Meat)接口的实现:
public class PigMeat implements Meat {
public void feed() {
System.out.println("养猪!");
}
public void enableEat() {
System.out.println("猪肉好吃!");
}
}
// 牛肉(CowMeat)是对肉(Meat)接口的实现:
public class CowMeat implements Meat {
public void feed() {
System.out.println("养牛!");
}
public void enableEat() {
System.out.println("牛肉好吃!");
}
}
// 我们可以定义买货人(Buyer)接口:
public interface Buyer {
public Fruit buyFruit(Fruit whichFruit);
public Meat buyMeat(Meat whichMeat);
}
// 我(MyBuyer)是对买货人(Buyer)接口的实现:
public class MyBuyer implements Buyer {
public Fruit buyFruit(Fruit whichFruit) {
return whichFruit;
}
public Meat buyMeat(Meat whichMeat) {
return whichMeat;
}
}
// 编写测试类:
public class MyBuyerAbstractTest {
public static void main(String args[]) {
Fruit apple = new Apple(); // 苹果实例
Meat big = new PigMeat(); // 猪肉实例
MyBuyer my = new MyBuyer(); // 我是买者的实例
my.buyFruit(apple).enableEat(); // 我买苹果
my.buyMeat(big).enableEat(); // 我买猪肉
}
}
说明:
Ø 抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象。这就是抽象工厂模式的用意。
Ø 抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。
Ø 抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品(Fruit)等级结构;而抽象工厂模式则需要面对多个产品等级结构(Fruit、Meat)。