设计模式二:工厂模式

在设计模式的的七大原则中提到过,要针对接口编程,而不是针对实现编程。比如这样写:

List<String> list = new ArrayList<>();

等号左侧用的是List类型(接口),而不是ArrayList类型(实现)。
但是,在等号右侧,我们不得不new一个具体类型,这样从某种程度上来说也是面向实现编程了,如果说以后我自己写了个新的ArrayList,想要替换掉原有的ArrayList。这时,就不得不修改这一行代码了,而且因为这个类使用很频繁,要修改的地方会非常多,这就是针对实现编程的缺点所在了,一旦发生改变,代码改动很大。
如果换下面这种方式呢?

List<String> list = ListFactory.newList(ListType.ARRAY_LIST);

注:这里ListType.ARRAY_LIST代表一个常量
在这里,通过一个静态方法去获取List,在该方法中,大致的实现是这样的:

public class ListFactory{
	public static List newList(String listType){
		switch(listType){
			case ListType.ARRAY_LIST:
				return new ArrayList();
			case .....
			...
		}
	}
}

这样,下次要把ArrayList的实现换掉,只需要修改ListFactory中的实现即可,且只需要改这一个地方。
上述就是一个简单工厂了。

1 简单工厂

需求:现有一披萨店,提供订购披萨的功能,顾客可以选择多种披萨,如cheese pizza,greek pizza等。

看看订购pizza的方法怎么写:

Pizza orderPizza(String type){
	Pizza pizza;
	switch(type){
		case "cheese":
			pizza = new CheesePizza();
			break;
		case "greek":
			pizza = new GreekPizza();
			break;
		case ...
		...
	}
	pizza.prepare();
	pizza.bake();
	pizza.cut();
	pizza.box();
	return pizza;
}

但是,pizza的种类是会不断增减的,那么orderPizza这个方法就需要不断修改。这时就可以使用简单工厂了。实现方法和上面说的差不多,将创建pizza的过程抽到工厂中即可。
这样似乎并没有解决多少问题,只是将代码的修改从orderPizze移到了工厂中,但是别忘了,创建pizza会出现在很多地方,就如同上面的创建ArrayList一样。把创建工作集中到工厂中,方便统一管理。

在上面的例子中,简单工厂是用静态方法来实现的,这种方法也被称为静态工厂。也可实例化一个工厂。如下:

public class PizzaStore{
	private PizzaFactory pizzaFactory;
	public PizzaStore(PizzaFactory pizzaFactory){
		this.pizzaFactroy = pizzaFactory;
	}
	public Pizza orderPizza(String type){
		Pizza pizza = pizzaFactory.createPizza(type);
		...
		return pizza;
	}
}

两种方法各有所长,静态工厂使用简单,但不能通过继承来改变创建行为,而实例化的实现方式可以。

2 工厂方法模式

接着pizza的例子,现在因为披萨的生意好,有人希望加盟,每家加盟店都可能想要提供不同风味的披萨,这收到开店地区的影响。
首先考虑使用简单工厂。每个PizzaStore都有一个工厂来创建披萨,即将上例中的PizzaStore和PizzaFactory多实现几遍。这显然是一个很糟糕的设计,每个加盟店都各自独立,且总店无法管理。比如总店要求所有的pizza制作流程都分为prepare,bake,pizza,box四步。这时可以考虑使用继承,所有的加盟店都要继承总店提供的PizzaStore,在pizzaStore中定义一个抽象的createPizza方法,交给子类实现,如下:

public abstract class PizzaStore{
	public Pizza orderPizza(String type){
		Pizza pizza = createPizza(type);
		...
		return pizza;
	}
	public abstract Pizza createPizza(String type);
}

这就是工厂方法模式了。它的核心是将对象的实例化推迟到子类实现

3 抽象工厂模式

在2中谈到用简单工厂方法来实现该需求的时候,每一个加盟店都有一个独立的披萨工厂,这样没法管理。如果在此基础上完成抽象一个工厂接口,所有的披萨工厂都要实现该接口,这样,PizzaStore就可以不用做成抽象的

public interface PizzaFactory{
	Pizza createPizza(String type);
}
public class PizzaStore{
	private PizzaFactory pizzaFactory;
	public PizzaStore(PizzaFactory pizzaFactory){
		this.pizzaFactroy = pizzaFactory;
	}
	public Pizza orderPizza(String type){
		Pizza pizza = pizzaFactory.createPizza(type);
		...
		return pizza;
	}
}

这样,所有的加盟店都使用同一个PizzaStore,但传入的工厂不一样,可以创建的pizza也不一样。这就是抽象工厂模式了。

总结

工厂模式的意义在于将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的解耦,从而提高项目的扩展性和维护性。

你可能感兴趣的:(设计模式)