所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合。工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。
理论介绍
- 工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
- 抽象工厂模式:提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。
应用场景
- 工厂方法模式:可以将你的客户代码从需要实例化的具体类中解耦。或者如果你目前还不知道将来需要实例化哪些具体类时,可以选择使用。使用方法简单,只需要继承成子类,并实现他的工厂方法。
- 抽象工厂模式:需要创建产品家族和想让制造的相关产品集合时,可以选择使用。这是通过对象的组合。
代码实现参考
工厂方法模式
//PizzaStore.java
package factory_pattern.factory1;
public abstract class PizzaStore {
//orderPizza()调用createPizza()
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//把工厂对象的这个方法移到这里来
abstract Pizza createPizza(String type);
}
将PizzaStore定义为抽象类,让每个地方具体的NYPizzaStore和ChicagoPizzaStore去继承PizzaStore。
package factory_pattern.factory1;
public class NYPizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
if (type.equals("cheese")){
return new NYStyleCheesePizza();
}else if (type.equals("veggie")){
return new NYStyleVeggiePizza();
}else if (type.equals("clam")){
return new NYStyleClamPizza();
}else if (type.equals("pepperoni")){
return new NYStylePepperoniPizza();
}else {
return null;
}
}
}
-------------------------------------------------------------------------------------
public class ChicagoPizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
if (type.equals("cheese")){
return new ChicagoCheesePizza();
}else if (type.equals("veggie")){
return new ChicagoVeggiePizza();
}else if (type.equals("clam")){
return new ChicagoClamPizza();
}else if (type.equals("pepperoni")){
return new ChicagoPepperoniPizza();
}else {
return null;
}
}
}
让每个具体的类的createPizza()创建各自风味的不同种类的Pizza。
package factory_pattern.factory1;
public class Test {
public static void main(String[] args) {
NYPizzaStore pizzaStore = new NYPizzaStore();
Pizza pepperoni = pizzaStore.orderPizza("pepperoni");
System.out.println(pepperoni.getClass().getSimpleName());
System.out.println("---------------------------------");
ChicagoPizzaStore chicagoPizzaStore = new ChicagoPizzaStore();
Pizza clam = chicagoPizzaStore.orderPizza("clam");
System.out.println(clam.getClass().getSimpleName());
}
}
那么只需要创建一个具体的PizzaStore,在orderPizza()方法中选择口味,就可以了。
这我们就利用Pizza工厂定制了Pizza。
抽象工厂方法
抽象工厂模式与前者虽然操作不一样,但目的一致。
这时考虑到需要建造一个原料工厂来生成原料。由于每个地区存在差异,将所有的原料抽象成一个接口。
package factory_pattern.factory2;
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
//...other ingredient...
}
同样需要具体的工厂类实现。
package factory_pattern.factory2;
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return null;
}
@Override
public Sauce createSauce() {
return null;
}
}
重做Pizza…
package factory_pattern.factory2;
public abstract class Pizza {
Dough dough;
Sauce sauce;
abstract void prepare();
void bake(){}
void cut(){}
void box(){}
}
package factory_pattern.factory2;
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
void prepare() {
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
}
}
总结一下,我们到底做了什么。我们引入新类型的抽象工厂,来创建Pizza原料家族(集合)。通过抽象工厂所提供的接口,可以创建产品的家族,利用这个接口书写代码,我们的代码将从实际工厂解耦,以便在不同的上下文中实现各式各样的工厂,制造出不同的产品。
补充
依赖倒置原则:不能让高层组件依赖低层组件,两者都应该依赖于抽象。