Head First Java 设计模式——工厂方法模式

本文介绍如何运用工厂方法模式和抽象工厂模式解决披萨店连锁经营中的多样化需求问题。通过逐步改进Pizza订单处理流程,展示了如何封装对象创建过程,以及如何根据不同地域定制口味。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        工厂方法模式,定义了了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

        抽象工厂模式,提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

        书中给出的是一个Pizza店的例子。假设你有一个pizza店,你可能会这样定义你的预定菜单:

Pizza orderPizza() {
		Pizza pizza = new Pizza();
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		return pizza;
	}


        你可能需要更多的pizza类型,于是会这样定义

Pizza orderPizza(String type) {
		Pizza pizza; 
		if(type.equals("cheese")) {
			pizza = new CheesePizza();
		} else if(type.equals("greek")) {
			pizza = new GreekPizza();
		} else if(type.equals("pepperoni")) {
			pizza = new PepperoniPizza();
		}
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		return pizza;
	}


        但是你以后可能又会增加或减少Pizza的类型,这时你就会发现哪些代码是会变的,哪些是不会变的。

        封装创建对象的代码,我们将创建对象移到orderPizza()之外。如下所示:

        我们称这个新对象为"工厂",orderPizza()就变成此对象的客户。接下来我们建立一个简单Pizza工厂

public class SimplePizzaFactory {
		public Pizza createPizza(String type) {
			Pizza pizza = null;
			
			if(type.equals("cheese")) {
				pizza = new CheesePizza();
			} else if(type.equals("greek")) {
				pizza = new GreekPizza();
			} else if(type.equals("pepperoni")) {
				pizza = new PepperoniPizza();
			} else if(type.equals("clam")) {
				pizza = new ClamPizza();
			} else if(type.equals("viggie")) {
				pizza = new ViggiePizza();
			} 
			return pizza;
		}
	}

        然后我们重做PizzaStore类

public  class PizzaStore {
		SimplePizzaFactory factory;
		
		public PizzaStore(SimplePizzaFactory factory) {
			this.factory = factory;
		}
		
		Pizza orderPizza(String type) {
			Pizza pizza; 
			pizza = factory.createPizza(type);
			pizza.prepare();
			pizza.bake();
			pizza.cut();
			pizza.box();
			return pizza;
		}
	}

        接下来我们可能会有不同地方的加盟店,不同的加盟店口味又会有所不同,例如纽约加盟店跟芝加哥加盟店,这个时候你可能会想到为每个地方建议一个工厂分别为NYPizzaFactory、ChicagoFactory。如果你想要预定一个Pizza,你就要像如下调用:

	NYPizzaFactory nyFactory = new NYPizzaFactory();
	PizzaStore nyStore = new PizzaStore(nyFactory);
	nyStore.orderPizza("Veggie");
	
	ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
	PizzaStore chicagoStore = new PizzaStore(chicagoFactory);
	chicagoStore.orderPizza("Veggie");


        但是在推广SimpleFactory时,加盟店采用你的工厂创建Pizza,但是其他部分,却开始采用他们自创的流程:烘烤的做法有些差异、不要切片、使用其他厂商的盒子。这时候,我们可以用工厂方法设计模式来解决问题,如下:

 

public abstract class PizzaStore {
		Pizza orderPizza(String type) {
			Pizza pizza; 
			//把createPizza()方法从工厂对象移回PizzaStore。
			pizza = createPizza(type);
			pizza.prepare();
			pizza.bake();
			pizza.cut();
			pizza.box();
			return pizza;
		}
		//把工厂对象移到这个方法中,作为一个抽象方法,允许子类自己实现这个方法,并保证了其他流程不被改变。
		protected abstract Pizza createPizza(String type);
	}


        开一家纽约加盟店

public class NYPizzaStore extends PizzaStore {
		Pizza createPizza(String item) {
			if(type.equals("cheese")) {
				pizza = new NYStyleCheesePizza();
			} else if(type.equals("greek")) {
				pizza = new NYStyleGreekPizza();
			} else if(type.equals("pepperoni")) {
				pizza = new NYStylePepperoniPizza();
			} else if(type.equals("clam")) {
				pizza = new NYStyleClamPizza();
			} 
		}
	}

public abstract class Pizza {
		String name;
		String dough;
		String sauce;
		ArrayList<String> toppings = new ArrayList<String>();

		public 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));
			}
		};
		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 official PizzaStore box");
		};
	}
	
	public class NYStyleCheesePizza extends Pizza {
		public NYStyleCheesePizza() {
			name = "NY Style Sauce and Cheese Pizza";
			doiugh = "Thin Crust Dough";
			sauce = "Marinara Sauce";
			toppings.add("Grated Reggiano Cheese");
		}
	}


 

	PizzaStore nyPizzaStore = new NYPizzaStore();
	Pizza pizza = nyPizzaStore.orderPizza("cheese");


        所有工厂模式都是用来封装对象的创建。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。组成元素有:创造者类(PizzaStore)、产品类(Pizza)。

        接下来我们用抽象工厂模式,
        首先建造原料工厂。

	public interface PizzaIngredientFactory {
		public Dough createDough();          //创建生面团
  	public Sauce createSauce();          //创建酱油
    	public Cheese createCheese();        //创建奶酪
		public Veggies[] createVeggies();    //创建蔬菜
		public Pepperoni createPepperoni();  //创建香肠
		public Clams createClam();           //创建蛤蚌
	}


        创建加盟店的原料工厂

public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
		public Dough createDough() {
			return new ThinCrustDough();
		}
		public Sauce createSauce() {
			return new MarinaraSauce();
		}
		public Cheese createCheese() {
			return new ReggianoCheese();
		}
		public Veggies[] createVeggies() {
			Veggies veggies[] {new Garlic(), new Onion(), new Mushroom(), new RedPepper()};
			return veggies;
		}
		public Pepperoni createPepperoni() {
			return new SlicedPepperoni();
		}
		public Clams createClam() {
			return new FreshClams();
		}
	}


        重做Pizza

        class Pizza {
		String name;
		Dough dough;
		Sauce sauce;
		Veggies veggies[];
		Cheese cheese;
		Pepperoni pepperoni;
		Clams clam;
		
		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 official PizzaStore box");
		};
		
		void setName(String name) {
			this.name = name;
		}
	}
	
	public class CheesePizza extends Pizza {
		PizzaIngredientFactory ingredientFactory;
		
		public CheesePizza(PizzaIngredientFactory factory) {
			this.ingredientFactory = factory;
		}
		
		void prepare() {
			System.out.println("Preparing " + name);
			dough = ingredientFactory.createDough();
			sauce = ingredientFactory.createSauce();
			cheese = ingredientFactory.createCheese();
		}
	}
	
	public class NYPizzaStore extends PizzaStore {
		protected Pizza createPizza(String item) {
			Pizza pizza = null;
			PizzaIngredientFactory ingredientFactory = new PizzaIngredientFactory();
			
			if(type.equals("cheese")) {
				pizza = new CheesePizza(ingredientFactory);
				pizza.setName("New York Style Cheese Pizza");
			} else if(type.equals("greek")) {
				pizza = new GreekPizza(ingredientFactory);
				pizza.setName("New York Style Greek Pizza");
			} else if(type.equals("pepperoni")) {
				pizza = new PepperoniPizza(ingredientFactory);
				pizza.setName("New York Style Pepperoni Pizza");
			} else if(type.equals("clam")) {
				pizza = new ClamPizza(ingredientFactory);
				pizza.setName("New York Style Clam Pizza");
			} 
		}
	}
	
	PizzaStore nyPizzaStore = new NYPizzaStore();
	Pizza pizza = nyPizzaStore.orderPizza("cheese");//这里可能会传入错误的值导致错误,因此我们可以采用枚举类型作为参数。


 

设计原则:

1、要依赖抽象,不要依赖具体类。

2、倒置原则:变量不可以持有具体类的应用;不要让类派生自具体类;不啊哟覆盖基类中已实现的方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值