【设计模式】HeadFirst设计模式(四):工厂模式

设计模式要求我们不应该针对实现编程,是为了降低耦合度,提高可维护性。当程序中出现“new”的时候,就证明程序在实例化一个具体类,所以用的是实现,而不是接口。如果代码绑着具体的类会导致代码更加脆弱,缺乏弹性。比如,需要创建一“个鸡蛋饼”这个对象,首先需要创建一个饼,然后创建一个鸡蛋,再然后把鸡蛋摊在饼上边,然后给饼翻翻,几分钟后就出炉了....(有点饿)。在这种情况下,新对象的建立是一个过程,如果我们需要在这个饼上边抹点辣椒酱,那肯定需要对类进行修改,违反了“对扩展开放,对修改关闭”的设计原则。这样就出现了一个问题:

     如何让客户直接构造出对象的实例,而不用在乎构造对象实例的具体细节?(就比如说,我想吃鸡蛋饼,直接就能买到,不需要知道这个鸡蛋饼如何做出来的)

具体实现:

首先,我们需要知道,工厂模式包含了三种:简单工厂(静态工厂)、工厂方法、抽象工厂。但是简单工厂并不属于GOF的23种设计模式

下边会用制作Pizza的例子来对三个模式进行说明:

假设你有一个Pizza店,并且你有很多种类型的Pizza,那么你会这样写代码:

<span style="font-size:18px;"><span style="font-size:14px;">Pizza orderPizza(String type){
		Pizza pizza;

		if(type.equals("chesse")){
			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;
	}</span></span>

根据参数传入类型type的不同,实例化不同的Pizza。

但是,你的竞争对象已经在菜单中加入了其它流行风味Pizza:ClamPizza(蛤蜊披萨)、VeggiePizza(素食披萨)。如果你想要赶上他们你就必须在自己的菜单中加入这些风味的披萨,而GreekPizza(希腊披萨)因为卖的不好所以去掉:

很明显的,orderPizza()方法不能够使得对修改关闭,但是我们已经知道哪些会改变,哪些不会改变,就可以使用封装了。

一、简单工厂模式:

要把创建Pizza的代码移动到另一个对象中,由这个新对象专职创建Pizza:

<span style="font-size:18px;"><span style="font-size:14px;">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;
	}
}</span></span>

问题:这么做似乎是把问题搬到另一个对象罢了?似乎没有什么好处?

答:SimplePizzaFactory可以有许多的客户,虽然目前仅仅只有orderPizza()方法是它的客户,但是在以后的扩展过程中可能会有很多个客户(但是如果把createPizza()这个方法放入到orderPizza()方法中的话,它只可能为orderPizza()一个服务)。所以,把创建Pizza的代码包装进一个类后,当以后实现改变的话,只需要修改这个类即可。我们正需要做的就是把实例化的过程,从客户的代码中删除。

缺点:因为是静态的,不能够通过继承来改变创建方法的行为。

下边,我们把其它的类写出来:

PizzaStore:是SimplePizzaFactory工厂类的“客户”,PizzaStor通过工厂类取得Pizza的实例

<span style="font-size:18px;"><span style="font-size:14px;">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;
	}
}</span></span>

Pizza:工厂的产品

<span style="font-size:18px;"><span style="font-size:14px;">abstract public class Pizza {
	String name;
	String dough;
	String sauce;
	ArrayList<String> toppings = new ArrayList<String>();

	public String getName() {
		return name;
	}

	public void prepare() {
		System.out.println("Preparing " + name);
	}

	public void bake() {
		System.out.println("Baking " + name);
	}

	public void cut() {
		System.out.println("Cutting " + name);
	}

	public void box() {
		System.out.println("Boxing " + name);
	}

	public String toString() {
		StringBuffer display = new StringBuffer();
		display.append("---- " + name + " ----\n");
		display.append(dough + "\n");
		display.append(sauce + "\n");
		for (int i = 0; i < toppings.size(); i++) {
			display.append(toppings.get(i) + "\n");
		}
		return display.toString();
	}
}
</span></span>

CheesePizza:

<span style="font-size:18px;"><span style="font-size:14px;">public class CheesePizza extends Pizza {
	public CheesePizza() {
		name = "Cheese Pizza";
		dough = "Regular Crust";
		sauce = "Marinara Pizza Sauce";
		toppings.add("Fresh Mozzarella");
		toppings.add("Parmesan");
	}
}</span></span>

VeggiePizza:

<span style="font-size:18px;"><span style="font-size:14px;">public class VeggiePizza extends Pizza {
	public VeggiePizza() {
		name = "Veggie Pizza";
		dough = "Crust";
		sauce = "Marinara sauce";
		toppings.add("Shredded mozzarella");
		toppings.add("Grated parmesan");
		toppings.add("Diced onion");
		toppings.add("Sliced mushrooms");
		toppings.add("Sliced red pepper");
		toppings.add("Sliced black olives");
	}
}</span></span>

ClamPizza:

<span style="font-size:18px;"><span style="font-size:14px;">public class ClamPizza extends Pizza {
	public ClamPizza() {
		name = "Clam Pizza";
		dough = "Thin crust";
		sauce = "White garlic sauce";
		toppings.add("Clams");
		toppings.add("Grated parmesan cheese");
	}
}</span></span>

写一个Main类:PizzaTestDrive

<span style="font-size:18px;"><span style="font-size:14px;">public class PizzaTestDrive {

	public static void main(String[] args) {
		SimplePizzaFactory factory = new SimplePizzaFactory();
		PizzaStore store = new PizzaStore(factory);

		Pizza pizza = store.orderPizza("cheese");
		System.out.println("We ordered a " + pizza.getName() + "\n");

		pizza = store.orderPizza("veggie");
		System.out.println("We ordered a " + pizza.getName() + "\n");
	}
}</span></span>

把UML类图画出来了:

二、工厂方法模式

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

现在,大家都希望能够在自家附近加盟你开的披萨店(其实就是想用你的招牌在他们那里开店啦)。但是,每个区域都会有差异,每家加盟店都想要提供不同风味的比萨(比方说纽约、芝加哥、加州),你想这样做:

<span style="font-size:18px;"><span style="font-size:14px;">//纽约风味的素食Pizza
NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza("Veggie");

//芝加哥风味的素食Pizza
ChicagePizzaFactory chicagoFactory = new ChicagePizzaFactory();
PizzaStore chicagoStore = new PizzaStore(chicagoFactory);
chicagoStore.orderPizza("Veggie");</span></span>

问题:但是,在推广你的方法的时候,别的加盟店的确是采用你的工厂创建比萨,但是其他部分却开始此采用他们自创的流程:烘烤的做法有差异、不要切片、使用其他厂商的盒子等等。

有一种做法可以让比萨制作活动局限于PizzaStore类,而同时又能让这些加盟店依然可以自由的制作本地区域的风味:

            把createPizza()方法放回到PizzaStore中,不过要把它设置成“抽象方法”:(原本是由一个对象负责所有具体类的实例化,现在通过对PizzaStor做一些转变,变成由一群子类来负责实例化)

声明一个工厂类:

<span style="font-size:18px;"><span style="font-size:14px;">public abstract class PizzaStore {
	//把createPizza()方法设置成抽象的,由子类做决定
	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;
	}
}</span></span>

然后声明两个具体工厂类:NYPizzaStore、ChicagoPizzaStore:

<span style="font-size:18px;"><span style="font-size:14px;">public class NYPizzaStore 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;
	}
}</span></span>
<span style="font-size:18px;"><span style="font-size:14px;">public class ChicagoPizzaStore extends PizzaStore {
	Pizza createPizza(String item) {
        	if (item.equals("cheese")) {
            		return new ChicagoStyleCheesePizza();
        	} else if (item.equals("veggie")) {
        	    	return new ChicagoStyleVeggiePizza();
        	} else if (item.equals("clam")) {
        	    	return new ChicagoStyleClamPizza();
        	} else if (item.equals("pepperoni")) {
            		return new ChicagoStylePepperoniPizza();
        	} else return null;
	}
}</span></span>

我们需要建立一个Pizza实体类:

<span style="font-size:18px;"><span style="font-size:14px;">public abstract class Pizza {
	String name; //名称
	String dough; //面团类型
	String sauce; //酱料
	ArrayList<String> toppings = new ArrayList<String>(); //作料

	void prepare() {
		System.out.println("准备 " + name);
		System.out.println("揉面团...");
		System.out.println("添加酱料...");
		System.out.println("添加作料: ");
		for (int i = 0; i < toppings.size(); i++) {
			System.out.println("   " + toppings.get(i));
		}
	}
	void bake() {
		System.out.println("烘烤25分钟");
	}
	void cut() {
		System.out.println("把Pizza对角切片");
	}
	void box() {
		System.out.println("把Pizza装盒子");
	}
	public String getName() {
		return name;
	}
}</span></span>

然后需要一些具体的子类,下边定义两个子类:纽约风味的芝士披萨(NYStyleCheesePizza)、芝加哥风味的芝士披萨(ChicageStyleCheesePizza)

<span style="font-size:18px;"><span style="font-size:14px;">public class NYStyleCheesePizza extends Pizza {
	public NYStyleCheesePizza() {
		name = "NY Style Sauce and Cheese Pizza";
		dough = "Thin Crust Dough";
		sauce = "Marinara Sauce";

		toppings.add("Grated Reggiano Cheese");
	}
}</span></span>
<span style="font-size:18px;"><span style="font-size:14px;">public class ChicagoStyleCheesePizza extends Pizza {
	public ChicagoStyleCheesePizza() {
		name = "Chicago Style Deep Dish Cheese Pizza";
		dough = "Extra Thick Crust Dough";
		sauce = "Plum Tomato Sauce";

		toppings.add("Shredded Mozzarella Cheese");
	}
	//可以覆盖cut()方法
	void cut() {
		System.out.println("Cutting the pizza into square slices");
	}
}</span></span>

我们把UML类图画出来:

如果我们需要一个纽约风味的芝士披萨,我们应该怎么做:

(1) 需要一个纽约比萨店:PizzaStore nyPizzaStore = new NYPizzaStore();

(2) 下订单:nyPizzaStore.orderPizza("cheese");

(3) orderPizza()方法调用createPizza()方法:Pizza pizza = createPizza("cheese");

(4) 最后经过:pizza.prepare()、pizza.bake()、pizza.cut()、pizza.box()才能完成Pizza

抽象工厂(放在了下一篇)

时间: 2024-12-15 20:00:05

【设计模式】HeadFirst设计模式(四):工厂模式的相关文章

C#设计模式系列:简单工厂模式(Simple Factory)

1.简单工厂模式简介 1.1>.定义 简单工厂模式定义一个Factory类,可以根据参数的不同返回不同类的实例,被创建的实例通常有共同的父类. 简单工厂模式只需要一个Factory类. 简单工厂模式又称为静态工厂模式,Factory类为静态类或包含静态方法. 1.2>.使用频率  中 2.简单工厂模式结构 2.1>.结构图 2.2>.参与者 简单工厂模式参与者: ◊ Product:抽象产品类,将具体产品类公共的代码进行抽象和提取后封装在一个抽象产品类中. ◊ ConcretePr

设计模式学习03—抽象工厂模式

1.动机与定义 工厂模式中,一个工厂仅仅能提供一个或一类产品,当产品种类较多,形成产品系列(比方我们要创建跨平台的button,菜单,文本框等等一系列GUI控件: 单纯使用工厂模式会产生大量工厂,并且后期维护也不方便,我们能够从产品中找到规律,假设产品等级相对固定,以后仅仅会新增产品族,那么我们就能够把整个产品族放到一个工厂创建,以后新增其它系统产品族也很方便,例如以下图: 这样的模式就是抽象工厂,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则须要面对多个产品等级结构,一个工厂等级结构能

(设计模式之一)浅析简单工厂模式

简单工厂模式 举个两个例子: 我输入两个数字和(+ - * /)其中一个符号,计算出两个数的结果. 饲养员让(狗 猫 鸟 猪)其中一个动物 叫 这里就是一个简单的工厂模式, 用户只需要提供他需要的接口,而不需要知道具体的实现 工厂判断用户提供的接口,创建对应的子类对象, 返回父类变量给用户(这里涉及里氏替换原则:声明父类变量替换子类对象) 当后面追加新的操作类例如:求根类  求平方类 , 从数据安全角度: 只需要创建新的类继承于Operation抽象类 ,从而不影响其他操作类(+ - * /),

常见的设计模式:单例模式、工厂模式、观察者模式、装饰模式与适配器模式

常见的设计模式:单例模式.工厂模式.观察者模式.装饰模式与适配器模式 这里可以阅读Terry Lee的设计模式系列来理解学习一下 1.4.1 单例模式 .NET设计模式(2):单件模式(Singleton Pattern)  http://terrylee.cnblogs.com/archive/2005/12/09/293509.html 1.4.2 抽象工厂模式 .NET设计模式(3):抽象工厂模式(Abstract Factory) http://terrylee.cnblogs.com/

初探设计模式(1)——工厂模式

从今天起,打算系统学习一下设计模式,先从工厂模式开始,本系列的文章只是对设计模式初步学习的总结,如有写的不对的地方欢迎指正. 什么是工厂模式呢?所谓工厂在我们的日常生活中就是生产产品的地方,如汽车工厂,玩具工厂等,在程序的世界中,设计到"生产产品"字眼的是什么?没错,就是创建对象! "工厂"通俗来说就是一个创建对象(产品)的地方.工厂模式(Factory Pattern)是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式,是 Java 中最常用的设

设计模式C++实现——抽象工厂模式

模式定义: 抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类. 抽象工厂允许客户使用抽象的接口来创建一组相关产品,而不需要知道实际产出的具体产品时什么.这样一来,客户就从具体的产品中被解耦了. 模式结构: 举例: 数据库访问程序设计,不同的数据库访问方式可能不一样,为了抽象对对不同数据库的访问,可以将数据库隐藏起来,提供统一的访问方式,用多态进行实现. UML设计: 编程实现及执行结果: #include <iostream> using namespace st

设计模式学习(二)-简单工厂模式

---恢复内容开始--- 简单工厂设计模式 简单工厂模式定义: 简单工厂设计模式又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式.在简单工厂模式中,可以根据参数的不同返回不同类的实例.简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类. 简单工厂主要分为如下几个角色 抽象产品(abstract product):为所有具体产品的抽象表现,一般为抽象类 具体产品(product):为抽象产品的具体实现 生成产品工厂(facto

Delphi 设计模式:《HeadFirst设计模式》Delphi7代码---工厂模式之简单工厂

简单工厂:工厂依据传进的参数创建相应的产品. http://www.cnblogs.com/DelphiDesignPatterns/archive/2009/07/24/1530536.html {<HeadFirst设计模式>工厂模式之简单工厂 } 3{ 产品类 } 4{ 编译工具 :Delphi7.0 } 5{ 联系方式 :[email protected]com } 6 7unit uProducts; 8 9interface 10 11type 12 TPizza = class(

Delphi 设计模式:《HeadFirst设计模式》Delphi代码---工厂模式之抽象工厂[转]

 1 2 {<HeadFirst设计模式>工厂模式之抽象工厂 } 3 { 抽象工厂的产品                       } 4 { 编译工具:Delphi7.0                  } 5 { E-Mail :[email protected]          } 6 7unit uPizzaIngredient; 8 9interface1011type12  TDough = class(TObject)13  end;1415  TThinCrustDoug

Delphi 设计模式:《HeadFirst设计模式》Delphi2007代码---工厂模式之工厂方法[转]

  1  2{<HeadFirst设计模式>工厂模式之工厂方法 }  3{ 产品类                              }  4{ 编译工具 :Delphi2007 for win32      }  5{ 联系方式 :[email protected]         }  6  7unit uProducts;  8  9interface 10 11type 12  { abstract Pizza } 13 14  TPizza = class abstract(