设计模式:工厂模式(Factory)
工厂模式是我们最常用的模式,相当于创建对象的new。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,只是用实现接口的方式创建对象,这种设计模式也是对象实例化的最佳方式。
工厂模式中有两种形态:
工厂方法(Factory Method)
抽象工厂(Abstract Factory)
这两种模式没有很明显的区别,区别在于需要创建对象的复杂程度上。
工厂模式:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。
我们来创建一个Animal接口。
Animal.java
public interface Animal {
void sing();
}
创建实现Animal接口的实体类:
Dog.java
public class Dog implements Animal {
@Override
public void sing() {
System.out.println("Inside Dog::sing() method.");
System.out.println("what's dog sing: 汪汪汪.");
}
}
Pig.java
public class Pig implements Animal {
@Override
public void sing() {
System.out.println("Inside Pig::sing() method.");
System.out.println("what's pig sing: 哼哼哼.");
}
}
Fox.java
public class Fox implements Animal {
@Override
public void sing() {
System.out.println("Inside Fox::sing() method.");
System.out.println("what's fox sing: 叮叮叮.");
}
}
创建一个工厂,生成基于给定信息的实体类的对象。
AnimalFactory.java
public class AnimalFactory {
//使用 getAnimal 方法获取动物类型的对象
public Animal getAnimal(String animalType){
if(animalType == null){
return null;
}
if(animalType.equalsIgnoreCase("dog")){
return new Dog();
} else if(animalType.equalsIgnoreCase("pig")){
return new Pig();
} else if(animalType.equalsIgnoreCase("fox")){
return new Fox();
}
return null;
}
}
使用该工厂,通过传递类型信息来获取实体类的对象。
FactoryPatternDemo.java
public class FactoryPatternDemo {
public static void main(String[] args) {
AnimalFactory animalFactory = new AnimalFactory();
// 获取 Dog 的对象,并调用它的 Sing 方法
Animal animal1 = animalFactory.getAnimal("dog");
// 调用 Dog 的 sing 方法
animal1.sing();
// 获取 pig 的对象,并调用它的 sing 方法
Animal animal2 = animalFactory.getAnimal("pig");
// 调用 pig 的 sing 方法
animal2.sing();
// 获取 fox 的对象,并调用它的 sing 方法
Animal animal3 = animalFactory.getAnimal("fox");
// 调用 fox 的 sing 方法
animal3.sing();
}
}
验证输出。
Inside Dog::sing() method.
what's dog sing: 汪汪汪.
Inside Pig::sing() method.
what's pig sing: 哼哼哼.
Inside Fox::sing() method.
what's fox sing: 叮叮叮.
优点:
1、一个调用者想创建一个对象,只要知道其名称就可以了,具备多态性。
2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
3、屏蔽产品的具体实现,调用者只关心产品的接口。
缺点:
每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
使用场景:
1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。
抽象工厂:抽象工厂模式(AbstractFactory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。与工厂模式相比,抽象工厂模式中的具体工厂不只是创建某一种产品,而是负责一组(产品族)。
起源
抽象工厂模式的起源或者最早的应用,是用于创建分属于不同操作系统的视窗构建。比如:命令按键(Button)与文字框(Text)都是视窗构建,在UNIX操作系统的视窗环境和Windows操作系统的视窗环境中,这两个构建有不同的本地实现,它们的细节有所不同。
在每一个操作系统中,都有一个视窗构建组成的构建家族。在这里就是Button和Text组成的产品族。而每一个视窗构件都构成自己的等级结构,由一个抽象角色给出抽象的功能描述,而由具体子类给出不同操作系统下的具体实现。
可以发现在上面的产品类图中,有两个产品的等级结构,分别是Button等级结构和Text等级结构。同时有两个产品族,也就是UNIX产品族和Windows产品族。UNIX产品族由UNIX Button和UNIX Text产品构成;而Windows产品族由Windows Button和Windows Text产品构成。
系统对产品对象的创建需求由一个工程的等级结构满足,其中有两个具体工程角色,即UnixFactory和WindowsFactory。UnixFactory对象负责创建Unix产品族中的产品,而WindowsFactory对象负责创建Windows产品族中的产品。这就是抽象工厂模式的应用,抽象工厂模式的解决方案如下图:
显然,一个系统只能够在某一个操作系统的视窗环境下运行,而不能同时在不同的操作系统上运行。所以,系统实际上只能消费属于同一个产品族的产品。
在现代的应用中,抽象工厂模式的使用范围已经大大扩大了,不再要求系统只能消费某一个产品族了。因此,可以不必理会前面所提到的原始用意。
摘抄自《JAVA与模式》之抽象工厂模式:http://www.cnblogs.com/java-my-life/archive/2012/03/28/2418836.html
我们将创建 Animal和 Color 接口和实现这些接口的实体类。下一步是创建抽象工厂类 AbstractFactory。接着定义工厂类 AnimalFactory 和 ColorFactory,这两个工厂类都是扩展了 AbstractFactory。然后创建一个工厂创造器/生成器类 FactoryProducer。
AbstractFactoryPatternDemo,我们的演示类使用 FactoryProducer 来获取 AbstractFactory 对象。它将向 AbstractFactory 传递动物信息 Animal(DOG / FOX / PIG),以便获取它所需对象的类型。同时它还向 AbstractFactory 传递颜色信息 Color(RED / GREEN / BLUE),以便获取它所需对象的类型。
我们复用之前对Animal接口以及实现其的接口类。
创建一个Animal接口。
Animal.java
创建实现Animal接口的实体类:
Dog.java
Pig.java
Fox.java
为颜色创建一个接口。
Color.java
public interface Color {
void fill();
}
创建实现接口的实体类。
Red.java
public class Red implements Color {
@Override
public void fill() {
System.out.println("Inside Red::fill() method.");
System.out.println("what's color: 红色的.");
}
}
Green.java
public class Green implements Color {
@Override
public void fill() {
System.out.println("Inside Green::fill() method.");
System.out.println("what's color: 绿色的.");
}
}
Blue.java
public class Blue implements Color {
@Override
public void fill() {
System.out.println("Inside Blue::fill() method.");
System.out.println("what's color: 蓝色的.");
}
}
为 Color 和 Animal 对象创建抽象类来获取工厂。
AbstractFactory.java
public abstract class AbstractFactory {
abstract Color getColor(String color);
abstract Animal getAnimal(String Animal);
}
创建扩展了AbstractFactory 的工厂类,基于给定的信息生成实体类的对象。
AnimalFactory1.java (防止和以前的AnimalFactory冲突)
public class AnimalFactory1 extends AbstractFactory {
@Override
Color getColor(String color) {
// TODO Auto-generated method stub
return null;
}
@Override
Animal getAnimal(String animalType) {
if(animalType == null){
return null;
}
if(animalType.equalsIgnoreCase("dog")){
return new Dog();
} else if(animalType.equalsIgnoreCase("pig")){
return new Pig();
} else if(animalType.equalsIgnoreCase("fox")){
return new Fox();
}
return null;
}
}
ColorFactory.java
public class ColorFactory extends AbstractFactory {
@Override
Color getColor(String color) {
if (color == null) {
return null;
}
if (color.equalsIgnoreCase("RED")) {
return new Red();
} else if (color.equalsIgnoreCase("GREEN")) {
return new Green();
} else if (color.equalsIgnoreCase("BLUE")) {
return new Blue();
}
return null;
}
@Override
Animal getAnimal(String Animal) {
// TODO Auto-generated method stub
return null;
}
}
创建一个工厂创造器/生成器类,通过传递形状或颜色信息来获取工厂。
FactoryProducer.java
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("ANIMAL")){
return new AnimalFactory1();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
使用FactoryProducer 来获取 AbstractFactory,通过传递类型信息来获取实体类的对象。
AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
// 获取动物工厂
AbstractFactory animalFactory = FactoryProducer.getFactory("ANIMAL");
// 获取 Dog 的对象,并调用它的 Sing 方法
Animal animal1 = animalFactory.getAnimal("dog");
// 调用 Dog 的 sing 方法
animal1.sing();
// 获取 pig 的对象,并调用它的 sing 方法
Animal animal2 = animalFactory.getAnimal("pig");
// 调用 pig 的 sing 方法
animal2.sing();
// 获取 fox 的对象,并调用它的 sing 方法
Animal animal3 = animalFactory.getAnimal("fox");
// 调用 fox 的 sing 方法
animal3.sing();
// 获取颜色工厂
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
// 获取颜色为 Red 的对象
Color color1 = colorFactory.getColor("RED");
// 调用 Red 的 fill 方法
color1.fill();
// 获取颜色为 Green 的对象
Color color2 = colorFactory.getColor("Green");
// 调用 Green 的 fill 方法
color2.fill();
// 获取颜色为 Blue 的对象
Color color3 = colorFactory.getColor("BLUE");
// 调用 Blue 的 fill 方法
color3.fill();
}
}
验证输出:
Inside Dog::sing() method.
what's dog sing: 汪汪汪.
Inside Pig::sing() method.
what's pig sing: 哼哼哼.
Inside Fox::sing() method.
what's fox sing: 叮叮叮.
Inside Red::fill() method.
what's color: 红色的.
Inside Green::fill() method.
what's color: 绿色的.
Inside Blue::fill() method.
what's color: 蓝色的.
优点:
分离接口和实现:客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已。也就是说,客户端从具体的产品实现中解耦。
切换产品族变得容易:对于增加新的产品族,抽象工厂模式很好地支持了开闭原则,只需要增加具体产品并对应增加一个新的具体工厂,对已有代码无须做任何修改(如:新增一种手柄操作支持)。
缺点:
产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。
本文参考了Patterns in Java 和 http://www.runoob.com