一、抽象工厂模式概述
抽象工厂模式定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
- 模式动机:
- 1.当系统提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式;
- 2.抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。
- 抽象工厂:一个工厂可以生产一系列(一族产品),极大减少了工厂类的数量。又叫做工具模式:抽象工厂模式中的具体工厂不只是创建一种产品,她负责一族产品;当一个工厂等级结构可以创建出分属于不同产品登记结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。
产品族是指位于不同等级结构中,功能相关联的产品组成的家族。
产品等级:产品的继承结构。
- 开闭原则的倾斜性
- 1.增加产品族:抽象工厂模式很好地支持了开闭原则,只需要增加具体产品并对应增加了一个新的具体工厂,对已有的代码无须做任何修改。
- 2.增加新的产品等级结构:需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,违背了开闭原则。
- 抽象工厂模式的优缺点:
- 优点:
- 1.隔离了具体类的生成,使得客户端并不需要知道什么被创建;
- 2.当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象;
- 3.增加新的产品族很方便,无需修改已有系统,符合开闭原则。
- 缺点:
- 增加心得产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便。违背了开闭原则。
- 优点:
- 模式适用环境:
- 1.当一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节;
- 2.系统中有多于一个的产品族,但每次只使用其中一个产品族;
- 3.属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来;
- 4.产品等级结构稳定,在设计完成之后不会向系统中增加新的产等级结构或者删除已有的产品等级结构。
二、代码实现
结构包含四个角色:
- 抽象工厂(Abstract Factory):一个工厂可以生产一系列(一族产品),极大减少了工厂类的数量。
- 具体工厂(ConcreteFactory):实现了在抽象工厂中声明的创建产品的方法,生成了一组具体产品,这些产品构成了一个产品族,每个产品都位于某个产品等级结构中。
- 抽象产品(AbstractProduct):它为每种产品声明接口,在抽象产品中声明了产品的所有业务方法。
- 具体产品(Concrete Product):定义具体工厂生产的具体产品对象,实现在抽象产品接口中声明的业务方法。
2.1 抽象工厂(两个抽象工厂:原料工厂和披萨总店)
package abstractFactory.Pizza;
//抽象工厂:披萨原料工厂
public interface PizzaIngredientFactory {
//封装了制造产品原料的方法,其中每个原料都是一个类
public Dough createDough();//面团
public Sauce createSauce();//酱料
public Cheese createCheese();//芝士
public Clams createClam();
}
package abstractFactory.Pizza;
//抽象工厂:抽象披萨店(总店)
public abstract class PizzaStore {
//生产具体类型的披萨店(每一个子店口味不一样,这里就是产生不同子店)
protected 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;
}
}
2.2 具体工厂(芝加哥原料厂、纽约原料厂和芝加哥分店、纽约分店)
package abstractFactory.Pizza;
//芝加哥原料工厂
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
// TODO Auto-generated method stub
return new ThickCrustDough();
}
@Override
public Sauce createSauce() {
// TODO Auto-generated method stub
return new PlumTomatoSauce();
}
@Override
public Cheese createCheese() {
// TODO Auto-generated method stub
return new MozzarellaCheese();
}
@Override
public Clams createClam() {
// TODO Auto-generated method stub
return new FrozenClams();
}
}
package abstractFactory.Pizza;
//纽约原料工厂
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
// TODO Auto-generated method stub
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
// TODO Auto-generated method stub
return new MarinaraSauce();
}
@Override
public Cheese createCheese() {
// TODO Auto-generated method stub
return new ReggianoCheese();
}
@Override
public Clams createClam() {
// TODO Auto-generated method stub
return new FreshClams();
}
}
package abstractFactory.Pizza;
//具体披萨分店:芝加哥分店
public class ChicagoPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String item) {
// TODO Auto-generated method stub
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory =
new ChicagoPizzaIngredientFactory();
if (item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("Chicago Style Cheese Pizza");
} else if (item.equals("clam")) {
pizza = new ClamPizza(ingredientFactory);
pizza.setName("Chicago Style Clam Pizza");
}
return pizza;
}
}
package abstractFactory.Pizza;
//具体披萨分店:纽约分店
public class NYPizzaStore extends PizzaStore {
@Override
protected Pizza createPizza(String item) {
// TODO Auto-generated method stub
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if (item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
} else if (item.equals("clam")) {
pizza = new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
}
return pizza;
}
}
2.3 抽象产品(原料抽象产品:Dough、Sauce、Cheese、Clam;披萨抽象产品:Pizza)
package abstractFactory.Pizza;
//抽象产品:披萨原料接口,面团
public interface Dough {
public String toString();
}
package abstractFactory.Pizza;
//抽象产品:披萨原料接口,酱料
public interface Sauce {
public String toString();
}
package abstractFactory.Pizza;
//抽象产品:披萨原料接口,芝士
public interface Cheese {
public String toString();
}
package abstractFactory.Pizza;
//抽象产品:,披萨原料接口
public interface Clams {
public String toString();
}
package abstractFactory.Pizza;
//抽象产品:披萨抽象类
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Cheese cheese;
Clams clam;
abstract void prepare();
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");
}
void setName(String name) {
this.name = name;
}
String getName() {
return name;
}
public String toString() {
StringBuffer result = new StringBuffer();
result.append("---- " + name + " ----\n");
if (dough != null) {
result.append(dough);
result.append("\n");
}
if (sauce != null) {
result.append(sauce);
result.append("\n");
}
if (cheese != null) {
result.append(cheese);
result.append("\n");
}
if (clam != null) {
result.append(clam);
result.append("\n");
}
return result.toString();
}
}
2.4 具体产品(具体原料:ThickCrustDough、ThinCrustDough、PlumTomatoSauce、MarinaraSauce、MozzarellaCheese、ReggianoCheese、FrozenClams、FreshClams;具体披萨:CheesePizza、ClamPizza)
package abstractFactory.Pizza;
//具体披萨原料,对应的原料工厂:ChicagoPizzaIngredientFactory
public class ThickCrustDough implements Dough {
public String toString() {
return "ThickCrust style extra thick crust dough";
}
}
package abstractFactory.Pizza;
//具体披萨原料,对应的原料工厂:NYPizzaIngredientFactory
public class ThinCrustDough implements Dough {
public String toString() {
return "Thin Crust Dough";
}
}
package abstractFactory.Pizza;
//具体披萨原料,对应原料工厂:ChicagoPizzaIngredientFactory
public class PlumTomatoSauce implements Sauce {
public String toString() {
return "Tomato sauce with plum tomatoes";
}
}
package abstractFactory.Pizza;
//具体披萨原料,对应的原料工厂:NYPizzaIngredientFactory
public class MarinaraSauce implements Sauce {
public String toString() {
return "Marinara Sauce";
}
}
package abstractFactory.Pizza;
//具体披萨原料,对应原料工厂ChicagoPizzaIngredientFactory
public class MozzarellaCheese implements Cheese {
public String toString() {
return "Shredded Mozzarella";
}
}
package abstractFactory.Pizza;
//具体披萨原料,对应原料工厂NYPizzaIngredientFactory
public class ReggianoCheese implements Cheese {
public String toString() {
return "Reggiano Cheese";
}
}
package abstractFactory.Pizza;
//具体披萨原料,对应的原料工厂:ChicagoPizzaIngredientFactory
public class FrozenClams implements Clams {
public String toString() {
return "Frozen Clams from Chesapeake Bay";
}
}
package abstractFactory.Pizza;
//具体披萨原料,对应的原料工厂:NYPizzaIngredientFactory
public class FreshClams implements Clams {
public String toString() {
return "Fresh Clams from Long Island Sound";
}
}
package abstractFactory.Pizza;
//具体披萨子类
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
void prepare() {
// TODO Auto-generated method stub
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
package abstractFactory.Pizza;
//具体披萨子类
public class ClamPizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
void prepare() {
// TODO Auto-generated method stub
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
2.5 main方法实现抽象工厂模式
package abstractFactory.Pizza;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
PizzaStore nyStore = new NYPizzaStore();
PizzaStore chicagoStore = new ChicagoPizzaStore();
//纽约子店点餐
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza + "\n");
//芝加哥子店点餐
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza + "\n");
//纽约子店点餐
pizza = nyStore.orderPizza("clam");
System.out.println("Ethan ordered a " + pizza + "\n");
//芝加哥子店点餐
pizza = chicagoStore.orderPizza("clam");
System.out.println("Joel ordered a " + pizza + "\n");
}
}
2.6 UML图
三、代码结构图
四、工厂方法模式与抽象工厂模式的总结
- 所有的工厂都是用来封装对象的创建;
- 简单工厂:虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类解耦;
- 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象;
- 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中;
- 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合;
- 工厂方法允许类将实例化延迟到子类进行。
- 抽象工厂创建相关的对象家族,而不需要依赖它们的具体类。
UML图对比
工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。