设计模式第五天——工厂模式

在这一次分享中,向大家介绍一下工厂模式。工厂模式简单的说就是将对象创建的细节封装起来,实现这样目的的方式有三种:简单工厂、工厂方法模式和抽象工厂模式。在介绍着几个方式之前,首先来向大家介绍一个设计原则—依赖倒置原则。

什么是依赖倒置原则呢?官方说:“要依赖抽象,不要依赖具体类”,这和针对接口编程很相似。通过一个例子让大家了解依赖倒置原则。

假设我要去披萨店点披萨,一共有3种披萨CheesePizza,VeggiePizza,ClamPizza。通过PizzaStore的orderPizza()方法来点披萨。代码是这样的。


import pizza.CheesePizza;
import pizza.ClamPizza;
import pizza.Pizza;
import pizza.VeggiePizza;
/**
 * 披萨店
 * @author wangpeiyu
 *
 */
public class PizzaStore {
	public Pizza orderPizza(String type){
		Pizza pizza=null;
		if(type.equals("cheese")){
			pizza=new CheesePizza();
		}else if(type.equals("veggie"))
		{
			pizza = new VeggiePizza();
		}else if(type.equals("clam"))
		{
			pizza = new ClamPizza();
		}
		return pizza;
	}

}

在UML中,将上述类间关系画出来是这样的。

可以看到PizzaStore类依赖Pizza及所有他的子类,这样导致依赖非常严重,高耦合。对于在上面的代码,你会发现,如果你要新增一种披萨,除了要新建一个Pizza子类外,还要在PizzaStore的orderPizza()方法中修改相应的代码,这样导致耦合度很高。

如果我们把orderPizza()方法中创建Pizza对象的代码块抽取出来,放到另外的一个对象中专门处理,如下面的代码。

PizzaStore类

import factory.PizzaFactory;
import pizza.CheesePizza;
import pizza.ClamPizza;
import pizza.Pizza;
import pizza.VeggiePizza;
/**
 * 披萨店
 * @author wangpeiyu
 *
 */
public class PizzaStore {
	public Pizza orderPizza(String type){
		Pizza pizza=null;
/*		if(type.equals("cheese")){
			pizza=new CheesePizza();
		}else if(type.equals("veggie"))
		{
			pizza = new VeggiePizza();
		}else if(type.equals("clam"))
		{
			pizza = new ClamPizza();
		}*/
		pizza = PizzaFactory.createPizza(type);
		/**
		 * 再执行其他的相关操作
		 */
		return pizza;
	}

}

PizzaFactory工厂类

package factory;
import pizza.CheesePizza;
import pizza.ClamPizza;
import pizza.Pizza;
import pizza.VeggiePizza;
/**
 * 披萨工厂类
 * 专职处理披萨对象的创建
 * 如果要创建一个披萨对象,直接找这个对象就可以了
 * @author wangpeiyu
 *
 */
public class PizzaFactory {
	/**
	 * 生成具体的披萨对象
	 * @param type 披萨的类型
	 * @return 返回生成的指定披萨实例
	 */
	public static Pizza createPizza(String type)
	{
		Pizza pizza=null;
		if(type.equals("cheese")){
			pizza=new CheesePizza();
		}else if(type.equals("veggie"))
		{
			pizza = new VeggiePizza();
		}else if(type.equals("clam"))
		{
			pizza = new ClamPizza();
		}
		return pizza;
	}
}

这时候PizzaStoreUML图是这样的。

你会发现依赖图原本由上而下的,现在倒置了。换句话说:不能让高层组件(PizzaStore,Pizza)依赖低层组件(Pizza子类),而且不管是高层还是低层组件,两者都应该依赖抽象。

上面将创建对象的代码块抽取出来,放到PizzaFactory中去实现的方式,我们成为简单工厂。这时候,如果你要增加一种披萨,PizzaStore中的所有代码都不需要更改,你只有修改专门负责创建pizza对象的PizzaFactory类中的createPizza方法就可以了。而且在其他任何地方用到创建Pizza对象也直接用PizzaFactory就可以了,这样即使需要修改也是修改一处,提高了代码的重用,降低了耦合。

下面来介绍一下另一种方式,工厂方法模式。

 改变一下需求,上面说的三种披萨各有二种风味的,分别为纽约风味和伦敦风味。因此及现在Pizza的子类就有6个了。分别为

NYCheesePizza,LDCheesePizza,NYVeggiePizza,LDVeggiePizza,NYClamPizza,LDClamPizza.

   传统我们是怎么实现的呢。

   PizzaStore类中的orderPizza()方法是代码这样的。

public Pizza orderPizza(String style,String type)
	{
		Pizza pizza = null;
		if(style.equals("NewYork")){
			if(type.equals("cheese")){
				pizza=new NYCheesePizza();
			}else if(type.equals("veggie"))
			{
				pizza = new NYVeggiePizza();
			}else if(type.equals("clam"))
			{
				pizza = new NYClamPizza();
			}
		}else if(style.equals("London")){
			if(type.equals("cheese")){
				pizza=new LDCheesePizza();
			}else if(type.equals("veggie"))
			{
				pizza = new LDVeggiePizza();
			}else if(type.equals("clam"))
			{
				pizza = new LDClamPizza();
			}
		}
		return pizza;
	}

你会发现,判断特别的多。如果还要增加新的pizza或者风味,那这么判断就不可想象了,非常容易错误。经过思考,我们可以将PizzaStore作为基类,创建一个抽象的方法createPizza(),不同的风味的披萨的创建作为一个子类,那这个子类就必须实现createPizza()方法,这个方法只创建属于这个子类风味的披萨。这样要创建不同风味的披萨,则创建相应的子类对象赋值给PizzaStore基类引用,利用多态,PizzaStore引用可以指向不同的风味,则可以创建不同的风味披萨了,而且即使要增加新的风味,则继承PizzaStore实现该特定风味的披萨的createPizza()方法就可以了。

    下面是代码的实现。

基类PizzaStore类的代码,PizzaStore类为抽象类,增加了一个抽象的方法createPizza(),子类必须要实现这个方法。

import factory.PizzaFactory;
import pizza.CheesePizza;
import pizza.ClamPizza;
import pizza.LDCheesePizza;
import pizza.LDClamPizza;
import pizza.LDVeggiePizza;
import pizza.NYCheesePizza;
import pizza.NYClamPizza;
import pizza.NYVeggiePizza;
import pizza.Pizza;
import pizza.VeggiePizza;
/**
 * 披萨店
 * @author wangpeiyu
 *
 */
public abstract class PizzaStore {
	public Pizza orderPizza(String type){
		Pizza pizza=null;
/*		if(type.equals("cheese")){
			pizza=new CheesePizza();
		}else if(type.equals("veggie"))
		{
			pizza = new VeggiePizza();
		}else if(type.equals("clam"))
		{
			pizza = new ClamPizza();
		}*/
		//这个是简单工厂实现
		//pizza = PizzaFactory.createPizza(type);
		//下面是工厂方法模式实现的
		  pizza = createPizza(type);
		/**
		 * 再执行其他的相关操作
		 */
		return pizza;
	}
	
	public abstract Pizza createPizza(String type);
	/**
	 * 传统的实现不同风味的披萨创建
	 * @param style 风味
	 * @param type  披萨的类型
	 * @return 返回指定风味的指定披萨
	 */
	/*public Pizza orderPizza(String style,String type)
	{
		Pizza pizza = null;
		if(style.equals("NewYork")){
			if(type.equals("cheese")){
				pizza=new NYCheesePizza();
			}else if(type.equals("veggie"))
			{
				pizza = new NYVeggiePizza();
			}else if(type.equals("clam"))
			{
				pizza = new NYClamPizza();
			}
		}else if(style.equals("London")){
			if(type.equals("cheese")){
				pizza=new LDCheesePizza();
			}else if(type.equals("veggie"))
			{
				pizza = new LDVeggiePizza();
			}else if(type.equals("clam"))
			{
				pizza = new LDClamPizza();
			}
		}
		return pizza;
	}*/
}

 

纽约风味的披萨的NYPizzaStore类代码,继承与PizzaStore类,必须实现PizzaStore类中的抽象方法createPizza().

import pizza.NYCheesePizza;
import pizza.NYClamPizza;
import pizza.NYVeggiePizza;
import pizza.Pizza;
/**
 * 纽约风味的披萨店
 * 专门创建纽约风味的pisa
 * @author wangpeiyu
 *
 */
public class NYPizzaStore extends PizzaStore {

	@Override
	public Pizza createPizza(String type) {
		Pizza pizza = null;
		if(type.equals("cheese")){
			pizza=new NYCheesePizza();
		}else if(type.equals("veggie"))
		{
			pizza = new NYVeggiePizza();
		}else if(type.equals("clam"))
		{
			pizza = new NYClamPizza();
		}
		return pizza;
	}

}

下面是伦敦风味的披萨类,与纽约的一致。

import pizza.LDCheesePizza;
import pizza.LDClamPizza;
import pizza.LDVeggiePizza;
import pizza.Pizza;
/**
 * 伦敦风味的披萨
 * 专门创建负责伦敦风味的披萨
 * @author wangpeiyu
 *
 */
public class LDPizzaStore extends PizzaStore {
	@Override
	public Pizza createPizza(String type) {
		Pizza pizza=null;
		if(type.equals("cheese")){
			pizza=new LDCheesePizza();
		}else if(type.equals("veggie"))
		{
			pizza = new LDVeggiePizza();
		}else if(type.equals("clam"))
		{
			pizza = new LDClamPizza();
		}
		return pizza;
	}
}

下面来创建一个测试类,来测试工厂方法模式。

package test;

import pizza.LDClamPizza;
import store.LDPizzaStore;
import store.NYPizzaStore;
import store.PizzaStore;

public class main {

	public static void main(String[] args) {
		//新建一个PizzaStore基类引用
		PizzaStore store=null;
		/**
		 * 小明点了一个纽约风味的cheese披萨
		 */
		//赋值纽约风味的对象
		store = new NYPizzaStore();
		store.orderPizza("cheese").tostring();
		/**
		 * 小红点了一个;伦敦风味的clam披萨
		 */
		//赋值纽约风味的对象
		store = new LDPizzaStore();
		store.orderPizza("clam").tostring();
	}

}

输出的结果为:

NYCheesePizza

LDClamPizza

可以看出已经订了相应风味的执行披萨。

现在我想在生产披萨对象的时候指定原料的产地,我们假设原料产地有两个地方,纽约原料产地和伦敦原料产地,NYSourceFactoryLDSourceFactory类。为了满足针对接口编程的原则,我们要建立一个原料产地的基类。SourceFactory,在创建披萨的时候要将原料产地对象传递进去。现在将代码修改后为:

SourceFactory

package factory;

/**
 * 抽象工厂模式
 * 原料工厂
 * @author wangpeiyu
 *
 */
public interface SourceFactory {
	public String createDough();
	public String createSauce();
}

下面是相应的原料工厂

纽约原料工厂:

package factory;
/**
 * 纽约的原料产地
 * @author wangpeiyu
 *
 */
public class NYSourceFactory implements SourceFactory {

	@Override
	public String createDough() {
		// TODO Auto-generated method stub
		return "ny dough";
	}

	@Override
	public String createSauce() {
		// TODO Auto-generated method stub
		return "ny sauce";
	}

}

伦敦原料工厂

package factory;
/**
 * 伦敦的原料产地
 * @author wangpeiyu
 *
 */
public class LDSourceFactory implements SourceFactory {

	@Override
	public String createDough() {
		// TODO Auto-generated method stub
		return "ld dough";
	}

	@Override
	public String createSauce() {
		// TODO Auto-generated method stub
		return "ld sauce";
	}

}

因为创建pizza要指定原料,所以pizza类中的材料要进行初始化,初始化为相应的原料。在不同的披萨中,添加的原料可能不同。所以在pizza中创建一个抽象的方法prepare,用来准备材料,在子类中必须实现这个方法,初始化相应的材料。

Pizza

package pizza;

public  abstract class Pizza {
	/**
	 * 名称
	 */
	protected String name;
	/**
	 * 面团类型
	 */
	protected String dough;
	/**
	 * 酱料类型,这是一种佐料
	 */
	protected String sauce;
	
	public void tostring()
	{
		System.out.println("Pizza");
	}
	public abstract void  prepare();
}

下面是NYCheesePizza披萨

package pizza;

import factory.SourceFactory;

public class NYCheesePizza extends Pizza {
	SourceFactory factory;
	public NYCheesePizza(SourceFactory factory) {
		this.factory = factory;
	}
	public void tostring()
	{
		System.out.println("NYCheesePizza  " + dough+"  "+sauce);
	}

	@Override
	public void prepare() {
		dough = factory.createDough();
		sauce = factory.createSauce();	
	}
}

package pizza;

import factory.SourceFactory;

public class LDCheesePizza extends Pizza {
	SourceFactory factory;
	public LDCheesePizza(SourceFactory factory) {
		this.factory = factory;
	}
	public void tostring()
	{
		System.out.println("LDCheesePizza  " + dough+"  "+sauce);
	}

	@Override
	public void prepare() {
		this.dough = factory.createDough();
		this.sauce = factory.createSauce();
	}
}

package pizza;

import factory.SourceFactory;

public class LDClamPizza extends Pizza {
	SourceFactory factory;
	public LDClamPizza(SourceFactory factory) {
		this.factory = factory;
	}
	public void tostring()
	{
		System.out.println("LDClamPizza  " + dough+"  "+sauce);
	}

	@Override
	public void prepare() {
		dough = factory.createDough();
		sauce  =factory.createSauce();
	}
}

package pizza;

import factory.SourceFactory;

public class LDVeggiePizza extends Pizza {
	SourceFactory factory;
	public LDVeggiePizza(SourceFactory factory) {
		this.factory =factory;
	}
	public void tostring()
	{
		System.out.println("LDVeggiePizza  " + dough+"  "+sauce);
	}

	@Override
	public void prepare() {
		dough = factory.createDough();
		sauce = factory.createSauce();	
	}
}

package pizza;

import factory.SourceFactory;

public class NYClamPizza extends Pizza {
	SourceFactory factory;
	public NYClamPizza(SourceFactory factory) {
		this.factory = factory;
	}
	public void tostring()
	{
		System.out.println("NYClamPizza  " + dough+"  "+sauce);
	}

	@Override
	public void prepare() {
		dough =factory.createDough();
		sauce= factory.createSauce();
		
	}
}

package pizza;

import factory.SourceFactory;
public class NYVeggiePizza extends Pizza{
	SourceFactory factory;
	public NYVeggiePizza(SourceFactory factory) {
		this.factory=factory;
	}
	public void tostring()
	{
		System.out.println("NYVeggiePizza  " + dough+"  "+sauce);
	}

	@Override
	public void prepare() {
		dough = factory.createDough();
		sauce =factory.createSauce();
	}
}

NYPizzaStore披萨店类

package store;
import factory.NYSourceFactory;
import pizza.NYCheesePizza;
import pizza.NYClamPizza;
import pizza.NYVeggiePizza;
import pizza.Pizza;
/**
 * 纽约风味的披萨店
 * 专门创建纽约风味的pisa
 * @author wangpeiyu
 *
 */
public class NYPizzaStore extends PizzaStore {
	NYSourceFactory factory=new NYSourceFactory();
	@Override
	public Pizza createPizza(String type) {
		Pizza pizza = null;
		if(type.equals("cheese")){
			pizza=new NYCheesePizza(factory);
		}else if(type.equals("veggie"))
		{
			pizza = new NYVeggiePizza(factory);
		}else if(type.equals("clam"))
		{
			pizza = new NYClamPizza(factory);
		}
		return pizza;
	}

}
伦敦披萨店类
package store;
import factory.LDSourceFactory;
import factory.NYSourceFactory;
import pizza.LDCheesePizza;
import pizza.LDClamPizza;
import pizza.LDVeggiePizza;
import pizza.Pizza;
/**
 * 伦敦风味的披萨
 * 专门创建负责伦敦风味的披萨
 * @author wangpeiyu
 *
 */
public class LDPizzaStore extends PizzaStore {
	LDSourceFactory factory=new LDSourceFactory();
	@Override
	public Pizza createPizza(String type) {
		Pizza pizza=null;
		if(type.equals("cheese")){
			pizza=new LDCheesePizza(factory);
		}else if(type.equals("veggie"))
		{
			pizza = new LDVeggiePizza(factory);
		}else if(type.equals("clam"))
		{
			pizza = new LDClamPizza(factory);
		}
		return pizza;
	}
}

在这里规定了NYPizzaStore商店用的是NYSourceFactory工厂的原料。但是真正的抽象工厂模式不是在这里,而是在各个Pizza的子类中,通过SourceFactory的引用factory去动态的创建原料,这里是创建了两种材料,createDoughcreateSauce

测试类:

package test;
import pizza.LDClamPizza;
import pizza.Pizza;
import store.LDPizzaStore;
import store.NYPizzaStore;
import store.PizzaStore;
public class main {
	public static void main(String[] args) {
		//新建一个PizzaStore基类引用
		PizzaStore store=null;
		Pizza pizza=null;
		/**
		 * 小明点了一个纽约风味的cheese披萨
		 */
		//赋值纽约风味的对象
		store = new NYPizzaStore();
		pizza = store.orderPizza("cheese");
		pizza.prepare();
		pizza.tostring();
		/**
		 * 小红点了一个;伦敦风味的clam披萨
		 */
		//赋值纽约风味的对象
		 store = new LDPizzaStore();
		 pizza = store.orderPizza("cheese");
		pizza.prepare();
		pizza.tostring();
	}

}

测试的结果是:

NYCheesePizza  ny dough ny sauce

LDCheesePizza  ld dough ld sauce

已经实现了动态的生成原料。

工厂方式模式和抽象工厂模式其实相似,但是也有不同。不同在于工厂方法模式是基于基类派生出来的,而且只能创建一个对象。而抽象工厂模式则是生产一系列的产品族,在这个例子中是生产了doughsauce原料,而且是在其他的对象中,通过组合来实现的。

总而言之,工厂模式就是将对象的创建细节封装起来。工厂方法模式是将对象的创建置于子类中实现,让子类决定创建哪些实例。抽象工厂模式则是将对象的创建置于工厂对象中,可以利用多态创建相应的产品族。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值