设计模式:工厂模式(Factory)

设计模式:工厂模式(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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值