一、简单工厂模式
1.概念
专门定义一个类来负责其他类的实例、被创建的实例通常具有共同的父类或接口,又称为静态工厂方法。
2.应用实例
披萨店生产不同类型的披萨,如ClamPizza、VeggiePizza等。
关系图:
实现代码:
Pizza类
import java.util.ArrayList;
import java.util.List;
/**
* 披萨抽象类,是所有类型Pizza的接口
* Created by hanxin on 2017/11/12.
*/
public abstract class Pizza {
String name;
String dough;
String sauce;
List toppings = new ArrayList();
public void prepare(){
System.out.println("Preparing "+name);
System.out.println("Tossing dough...");
System.out.println("Adding saucce...");
for(int i=0;i<toppings.size();i++){
System.out.println(" "+toppings.get(i));
}
}
public void bake(){
System.out.println("Bake for 25 minutes at 350");
}
public void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
public void box(){
System.out.println("Place pizza in offical PizzaStore box");
}
public String getName(){
return name;
}
}
SimplePizzaFactory类
/**
* 工厂类,生产各种Pizza实例
* Created by hanxin on 2017/11/12.
*/
public class SimplePizzaFactory {
//创建对象的工厂方法,一般为静态方法
public static Pizza creatPizza(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;
}
}
PizzaStore类
/**
* 披萨商店,是披萨工厂类的顾客
* Created by hanxin on 2017/11/12.
*/
public class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza = SimplePizzaFactory.creatPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.bake();
return pizza;
}
}
VeggiePizza 、PepperoniPizza、CheesePizza、ClamPizza类(实现一个,其他类似)
/**
* Created by hanxin on 2017/11/12.
*/
public class CheesePizza extends Pizza {
public CheesePizza(){
this.name = "cheesePizza";
}
}
测试类
/**
* Created by hanxin on 2017/11/12.
*/
public class Test {
public static void main(String[] args) {
PizzaStore store = new PizzaStore();
store.orderPizza("cheese");
}
}
3.优缺点
优点:
- 工厂类含有必要的逻辑判断,可以决定什么时候创建哪一个产品实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品:简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象;
- 客户端无需知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量;
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程序上提高了系统的灵活性。
缺点:
- 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响;
- 使用简单工厂模式将会增加系统中类的个数,在一定程度上增加了系统的复杂度和理解难度;
- 系统扩展困难,一旦添加新产品,就不得不修改工厂逻辑,在产品类型较多时有可能造成工厂逻辑过于复杂不利于系统的扩展和维护;
- 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
二、工厂方法模式
1.概念
定义一个用于创建对象的接口,让子类决定实例化哪个类,工厂方法使一个类的实例化延迟到其子类。
2.应用实例
披萨加盟店,不同区域的披萨店都有自己独特的风味,如NYStylePizzaStore、ChicagoStylePizzaStore等。
关系图:
Pizza类
import java.util.ArrayList;
import java.util.List;
/**
* 披萨抽象类,是所有类型Pizza的接口
* Created by hanxin on 2017/11/12.
*/
public abstract class Pizza {
String name;
String dough;
String sauce;
List toppings = new ArrayList();
public void prepare(){
System.out.println("Preparing "+name);
System.out.println("Tossing dough...");
System.out.println("Adding saucce...");
for(int i=0;i<toppings.size();i++){
System.out.println(" "+toppings.get(i));
}
}
public void bake(){
System.out.println("Bake for 25 minutes at 350");
}
public void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
public void box(){
System.out.println("Place pizza in offical PizzaStore box");
}
public String getName(){
return name;
}
}
PizzaStore类
/**
* 披萨店抽象类
* Created by hanxin on 2017/11/12.
*/
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
public abstract Pizza createPizza(String type);
}
NYStylePizzaStore类
/**
* Created by hanxin on 2017/11/12.
*/
public class NYStylePizzaStore extends PizzaStore {
@Override
public 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();
}
return null;
}
}
ChicagoStylePizzaStore类
/**
* Created by hanxin on 2017/11/12.
*/
public class ChicagoStylePizzaSttore extends PizzaStore {
@Override
public 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();
}
return null;
}
}
NYStyleCheesePizza类(其他类似)
/**
* Created by hanxin on 2017/11/12.
*/
public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza(){
this.name = "NYStyleCheesePizza";
this.dough = "Thin Crust Dough";
this.sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
}
}
ChicagoStyleCheesePizza类(其他类似)
/**
* Created by hanxin on 2017/11/12.
*/
public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza(){
this.name = "NYStyleCheesePizza";
this.dough = "Thin Crust Dough";
this.sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
}
}
测试:
/**
* Created by hanxin on 2017/11/12.
*/
public class Test {
public static void main(String[] args) {
PizzaStore store = new NYStylePizzaStore();
store.orderPizza("cheese");
}
}
优点:
- 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏具体产品类将被实例化这一细节,用户只需关心所需产品对应的工厂,无需关心创建细节,甚至无需知道具体产品类的类名;
- 基于工厂角色和产品角色多态性的设计是工厂方法模式的关键,它能够使工厂自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装到具体工厂内部。工厂方法模式,又称为多态性工厂模式,正是因为所有的具体工厂类都具有同一抽象父类;
- 使用工厂方法模式在系统中加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其它的具体工厂和具体产品,而只需要添加一个具体工厂和具体产品就可以了,这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
缺点:
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销;
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到反射机制等技术,增加了系统的实现难度。
三、抽象工厂模式
1.概念
提供一个创建一系列或互相依赖的对象的接口,而无需指定它们的具体类。
2.应用实例
为披萨店建造原料工厂,每个店铺都有独特的原料提供商。
关系图:
实现代码:
Pizza类
import java.util.ArrayList;
import java.util.List;
/**
* 披萨抽象类,是所有类型Pizza的接口
* Created by hanxin on 2017/11/12.
*/
public abstract class Pizza {
String name;
Dough dough;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clams;
Sauce sauce;
List toppings = new ArrayList();
abstract void prepare();
public void bake(){
System.out.println("Bake for 25 minutes at 350");
}
public void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
public void box(){
System.out.println("Place pizza in offical PizzaStore box");
}
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
PizzaStore类
/**
* 披萨店抽象类
* Created by hanxin on 2017/11/12.
*/
public abstract class PizzaStore {
public Pizza orderPizza(String type){
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
public abstract Pizza createPizza(String type);
}
NYStylePizzaStore、ChicagoStylePizzaStore类
/**
* Created by hanxin on 2017/11/12.
*/
public class NYStylePizzaStore extends PizzaStore {
@Override
public Pizza createPizza(String type) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if(type.equals("cheese")){
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
}else if(type.equals("veggie")){
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Veggie Pizza");
}else if(type.equals("clam")){
pizza = new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
}else if(type.equals("pepperoni")){
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style Peppernoi Pizza");
}
return pizza;
}
}
CheesePizza、VeggiePizza、ClamPizza、PepperoniPizza类
import java.util.Arrays;
/**
* Created by hanxin on 2017/11/12.
*/
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory = ingredientFactory;
}
@Override
void prepare() {
System.out.println("preparing "+name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
@Override
public String toString() {
return "CheesePizza{" +
"name='" + name + '\'' +
", dough=" + dough +
", veggies=" + Arrays.toString(veggies) +
", cheese=" + cheese +
", pepperoni=" + pepperoni +
", clams=" + clams +
", sauce=" + sauce +
", toppings=" + toppings +
'}';
}
}
其他实体类略......
3.优缺点
优点:
- 隔离了具体类的创建,使得用户不需要知道创建的细节;
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用一个产品族中的对象;
缺点:
- 添加新的产品对象时,难以扩展抽象工厂以便生成新种类的产品;