生成器模式:将一个复杂对象的构建与呈现分开,以便相同的构造过程能够根据不同需要创建不同的形式。
工厂方法模式:提供一个创建一个示例的接口,但是允许子类决定实例化哪个类,即不同的子类可以实例化不同的对象。
原型模式:先实例化一个类,然后克隆或者拷贝该类来构建新的实例。可以用共有方法进一步修改这些实例。
单件模式:某个类只能有一个实例。提供一个全局访问点。(可拓展到有限个实例)
简单工厂
意图:提供一个类,由它负责根据一定的条件创建某一具体类的实例
考虑我们开了一家披萨店,客户可以通过调用orderPizza方法来订餐。
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
我们使用一个工厂来制作各种披萨,而无需关心是哪种具体的批塞,因为工厂可以根据我们传进去的参数自己判断制造何种披萨。
public class SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;
if (type.equals("cheese")) {
pizza = new CheesePizza();
} else if (type.equals("pepperoni")) {
pizza = new PepperoniPizza();
} else if (type.equals("clam")) {
pizza = new ClamPizza();
} else if (type.equals("veggie")) {
pizza = new VeggiePizza();
}
return pizza;
}
}
抽象类Pizza的定义如下:
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
void prepare() {
System.out.println("Preparing " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for (int i = 0; i < toppings.size(); i++) {
System.out.println(" " + toppings.get(i));
}
}
void bake() {
System.out.println("Bake for 25 minutes at 350");
}
void cut() {
System.out.println("Cutting the pizza into diagonal slices");
}
void box() {
System.out.println("Place pizza in official PizzaStore box");
}
}
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
角色及其职责:
- 工厂(Creator)角色:如上图中的SimplePizzaFactory类。简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
- 抽象(Product)角色:如上图中的Pizza抽象类。简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
- 具体产品(Concrete Product)角色:如上图中的CheesePizza类、VeggiePizza类和ClamPizza类。简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。一般来讲它是抽象产品类的子类,实现了抽象产品类中定义的所有接口方法,也可以覆盖父类中的方法。
模式的特点:
- 优点:简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。在这个模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。
- 缺点:体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,所以"高内聚"方面做的并不好。另外,当系统中的具体产品类不断增多时,可能会出现要求工厂类也要做相应的修改,扩展性并不很好。
工厂方法模式
意图:定义一个用户创建对象的接口,让子类决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到其子类。这里的“决定”并不是指模式允许子类在运行时刻做决定,而是指在编写创建者类(Creator)时(如编写AnOperation()方法时),不需要知道实际创建的产品是哪一个。选择了使用哪个子类,自然就决定了实际创建的产品是什么。
依然考虑我们的披萨店。现在生意很好,我们有资本去开分店了!比如我们希望去北京、杭州、济南开不同的分店,但是由于存在地区差异,每家分店可能想要提供不同风味的批塞。如果使用简单工厂,我们可以写出三种不同的工厂,分别是BeijingPizzaFactory、HangzhouPizzaFactory、JinanPizzaFactory,那就会变成下面这个样子。
SimplePizzaFactory bjFactory = new BeijingPizzaFactory();
PizzaStore bjStore = new PizzaStore(bjFactory);
SimplePizzaFactory hzFactory = new HangzhouPizzaFactory();
PizzaStore hzStore = new PizzaStore(hzFactory);
然而,分店提出来他们想要采用自创的流程:烘烤的方法有些差异、不要切片、使用其他厂商的盒子等等。如果还是采用上面的方法,就会发现,因为大家都是采用同一个“客户”(PizzaStore),所以所有的流程必然都是相同的(都是PizzaStore中实现的orderPizza方法),这样做肯定是不行了。但是我们又希望大家使用同一个框架,同时又保持一定的弹性。这时工厂方法就登场了!
这个框架就是我们定义的一个PizzaStore的抽象类,它定义了所有分店的基本流程(框架),但允许子类继承并决定具体是怎样实现的(有弹性)。
public abstract class PizzaStore {
abstract Pizza createPizza(String item);
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
而每个分店只需继承这个类,实现自己的工厂方法,createPizza,即可。
public class BJPizzaStore extends PizzaStore {
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
return new NYStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else return null;
}
}
而且,每个分店还可以覆盖父类中的orderPizza方法,实现自己的创新!
除此之外,我们的披萨的种类也更多了,因为不同地区又研发出了不同口味的披萨,而且制作方法也可能发生了改变。
public class ChicagoStylePepperoniPizza extends Pizza {
public ChicagoStylePepperoniPizza() {
name = "Chicago Style Pepperoni Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
toppings.add("Black Olives");
toppings.add("Spinach");
toppings.add("Eggplant");
toppings.add("Sliced Pepperoni");
}
void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
与简单工厂相比,它们之间的差异如下:
- 虽然每个具体的商店(BJPizzaStore)看起来很像一个SimplePizzaFacoty,但是这里的商店是扩展自一个类,这个类中有一个抽象方法createPizza(),每个店实现自己的方法。而在简单工厂中,这个抽象方法是一个PizzaStore使用的对象。也就是说,简单工厂使用的是对象,而工厂方法使用的是方法。
- 简单工厂把全部事情在同一个地方做完,然后工厂方法却是建立了一个框架,剩下的让子类自己搞去吧。比如orderPizza()方法提供了一般框架,以便创建披萨,orderPizza()依赖工厂方法创建具体的类。
总结一下工厂方法。
- Creator是一个抽象类,它实现了所有操纵产品的方法