Java设计模式之三——工厂模式

转眼又是一个周末,我收获了很多,你呢?

一、前言

记得上个周末详细讲到了策略模式,并且最后还引出了一个策略模式带来的问题——导致系统中的类急剧膨胀。今天,就来介绍如何解决策略模式带来的问题,那就是工厂模式。

二、工厂模式

1、什么是工厂模式

我们都知道,在开发一个系统的过程中,会创建很多对象来处理我们的业务逻辑。我们创建对象最常用的方法就是使用Java的new关键字,通过这个关键字,我们很容易就可创建一个对象,然后可以调用该对象的方法完成我们的业务逻辑。但是,有过大项目经验的童鞋们应该知道,系统中的有些对象的创建并不是简简单单的new关键字那么简单,尤其是对于一些具有复杂依赖关系的对象,创建的过程就更加复杂;简单来说,我们可能不仅要为其做一些计算或者初始化的设置工作,可能还需要去创建其引用的一系列资源;而这些复杂的衣领关系我们都是要事先知晓,否则就可能导致对象创建失败。

2、问题的引出

我们该如何方便的创建出对象,而不必去关心对象创建过程中复杂的内部过程及其实现细节呢?

3、问题解决

工厂模式:通过创建一个工程来帮助我们创建对象。

三、工厂模式的分类和各自的差异

工厂模式主要的作用是提供一个总的入口,我们通过这个总的入口去创建我们需要的一些复杂对象,从而提高我们系统编码的灵活性和可扩展性。

1、工厂模式可以大致分为三类,其实主要是分为两类(简单工厂模式可以看为是工厂方法模式的一种特例,故两者可归为一类),分别如下:

1)简单工厂模式(Simple Factory Pattern)

2)工厂方法模式(Factory Method Pattern)

3)抽象工厂模式(Abstract Factory Pattern)

我们从名字就可以知道,这三种模式从上往下会逐步变得抽象,但是三个分类又具有其共性。

2、角色

1)工厂方法模式涉及到的角色:

一个抽象工厂角色,可以派生出多个具体工厂角色。

一个抽象产品角色,可以派生出多个具体的产品角色。

每个具体的工厂角色只能创建一个具体的产品角色的实例。

2)抽象工厂模式设计到的角色

一个抽象工厂角色,可以派生出多个具体的工厂角色。

多个抽象的产品角色,每个抽象的产品角色可以派生出多个具体产品角色。

每个具体工厂角色可以创建多个具体的产品角色的实例。

3、区别

工厂方法模式只有一个抽象产品角色,而抽象工厂模式可以有多个抽象产品角色。

工厂方法模式的具体工厂角色只能创建一个具体的产品角色的实例,而抽象工厂模式可以创建多个具体产品角色的实例。

四、工厂模式的实现

在看工厂模式实现之前,我们先来看下我们常用的创建对象的实现方式:

class AscendSeriesPhone {
	
	public AscendSeriesPhone() {

		System.out.println("华为创造Ascend系列手机");
	}
}

class HonourSeriesPhone {
	
	public HonourSeriesPhone() {
		
		System.out.println("华为创造Honour系列手机");
	}
}

class GoldSeriesPhone {
	
	public GoldSeriesPhone() {

		System.out.println("华为创造Gold系列手机");
	}	
}

public class ObjectCreateTest {

	public static void main(String[] args) {

		AscendSeriesPhone ascendSeriesPhone = new AscendSeriesPhone();
		
		HonourSeriesPhone honourSeriesPhone = new HonourSeriesPhone();
		
		GoldSeriesPhone goldSeriesPhone = new GoldSeriesPhone();
	}
}

从上面的代码我们知道,我们在创建对象的时候,客户端(在上面的例子就是main()方法)和需要创建的对象仅仅的耦合在一起;为了降低耦合性,我们使用简单工厂模式对上面的实现进行一些改造。

1、简单工厂模式:

//抽象产品角色
abstract class Phone {
	
	public Phone() {
		
	}
}

//具体产品角色
class AscendSeriesPhone extends Phone{
	
	public AscendSeriesPhone() {

		System.out.println("华为创造Ascend系列手机");
	}
}

//具体产品角色
class HonourSeriesPhone extends Phone {
	
	public HonourSeriesPhone() {
		
		System.out.println("华为创造Honour系列手机");
	}
}

//具体产品角色
class GoldSeriesPhone extends Phone {
	
	public GoldSeriesPhone() {

		System.out.println("华为创造Gold系列手机");
	}	
}

class Factory {
	
	public Phone createPhone(int key) {
		switch (key) {
		case 1:
			return new AscendSeriesPhone();
		case 2:
			return new HonourSeriesPhone();
		case 3:
			return new GoldSeriesPhone();
		default:
			break;
		}
		return null;
	}
}

//客户端
public class SimpleFactoryPattern {

	public static void main(String[] args) {

		Factory factory = new Factory();
		factory.createPhone(1);
		factory.createPhone(2);
		factory.createPhone(3);
	}
}

1)说明:由于简单工厂模式是最原始的对象创建模式,相比其他两种来说,用的最多也是最简单的一种,因此这里没有画相应的UML类图。

2)分析:从简单工厂模式代码可知,客户端在创建对象的时候,并不需要考虑复杂的对象关系,而只需要通过工厂类的createPhone()就可以获取自己指定需要创建的那个对象。这对于上面的那三个产品角色来说,很好的符合了OOP中的开闭原则,即对扩展开放,对修改封闭。

3)问题:虽然简单工厂模式为我们创建对象时解决了一些明显问题,但是简单工厂模式也有不足之处。假如我们要新添加一种产品角色,那么在工厂角色的createPhone()方法中就必须再写一个case。这样做有与刚刚说的开闭原则相违背。

于是我们再次对其进行改造,这次我们是用工厂方法模式。

2、工厂方法模式:

1)工厂方法模式相关角色的UML类图及其关系如下:


2)事例代码如下:

产品相关角色

/**
 * 
 * @ClassName: Phone
 * @Description: 抽象产品角色
 * @author admin
 * @date 2016年12月10日 上午11:14:54
 * @version V1.0
 */
public abstract class Phone {

	public Phone() {
		
	}
}
/**
 * 
 * @ClassName: AscendSeriesPhone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:15:28
 * @version V1.0
 */
public class AscendSeriesPhone extends Phone {
	
	public AscendSeriesPhone() {

		System.out.println("创造Ascend系列的华为品牌手机");
	}
}

/**
 * 
 * @ClassName: HonourSeriesPhone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:15:42
 * @version V1.0
 */
public class HonourSeriesPhone extends Phone {
	
	public HonourSeriesPhone() {

		System.out.println("创造Honour系列的华为品牌手机");
	}
}
/**
 * 
 * @ClassName: GoldSeriesPhone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:15:58
 * @version V1.0
 */
public class GoldSeriesPhone extends Phone {
	
	public GoldSeriesPhone() {

		System.out.println("创造Gold系列的华为品牌手机");
	}
}
工厂相关角色

/**
 * 
 * @ClassName: AbstractFactory
 * @Description: 抽象工厂角色-创造华为品牌手机
 * @author admin
 * @date 2016年12月10日 上午11:17:50
 * @version V1.0
 */
public abstract class AbstractFactory {

	public abstract Phone createHuaWeiSeriesPhone();
}
/**
 * 
 * @ClassName: AscendSeriesPhoneFactory
 * @Description: 具体工厂角色-创造Ascend系列的华为品牌手机
 * @author admin
 * @date 2016年12月10日 上午11:20:08
 * @version V1.0
 */
public class AscendSeriesPhoneFactory extends AbstractFactory {

	@Override
	public Phone createHuaWeiSeriesPhone() {

		return new AscendSeriesPhone();
	}
}
/**
 * 
 * @ClassName: HonourSeriesPhoneFactory
 * @Description: 具体工厂角色-创造Honour系列的华为品牌手机
 * @author admin
 * @date 2016年12月10日 上午11:22:24
 * @version V1.0
 */
public class HonourSeriesPhoneFactory extends AbstractFactory {

	@Override
	public Phone createHuaWeiSeriesPhone() {

		return new HonourSeriesPhone();
	}
}
/**
 * 
 * @ClassName: GoldSeriesPhoneFactory
 * @Description: 具体工厂角色-创造Gold系列的华为品牌手机
 * @author admin
 * @date 2016年12月10日 上午11:23:07
 * @version V1.0
 */
public class GoldSeriesPhoneFactory extends AbstractFactory {

	@Override
	public Phone createHuaWeiSeriesPhone() {

		return new GoldSeriesPhone();
	}
}
客户端

/**
 * 
 * @ClassName: Customer
 * @Description: 客户端
 * @author admin
 * @date 2016年12月10日 上午11:24:14
 * @version V1.0
 */
public class Customer {

	public static void main(String[] args) {
		
		AbstractFactory factory = new AscendSeriesPhoneFactory();
		factory.createHuaWeiSeriesPhone();
		
		factory = new HonourSeriesPhoneFactory();
		factory.createHuaWeiSeriesPhone();
		
		factory = new GoldSeriesPhoneFactory();
		factory.createHuaWeiSeriesPhone();
	}
}
3)分析:相比于简单工厂模式,假如需要新添加一种产品角色,那么我们只需要再写一个具体产品角色并让其继承抽象产品角色;用时也要写一个具体工厂角色且让其继承抽象工厂角色;然后在具体工厂角色中进行具体产品角色的创建。这样就避免了记得工厂模式中的需要改动工厂角色中的判断逻辑的问题。

4)问题引出:从上面代码可以看出,由于工厂方法的加入,使得我们系统中的类的数量急剧增长。假如还需要添加新的产品类,那么我们就又得在写一套产品角色及其创建该角色的工厂角色的代码。这显然不是我们希望看到的。
这个问题的处理我们在这暂且不做过多说明,本篇文章主要是为了说明工厂模式。
3、抽象工厂模式

我们都知道,IT界中的需求是不断变化的,客户的需求是不断增加的。随着客户的要求越来越高,在拥有了手机的同时,还想拥有配对的耳机,我们怎么办?继续创造呗。这时候就该抽象工厂模式出场了。

1)抽象工厂模式相关角色的UML类图及其关系如下:


2)事例代码如下:

产品相关角色

/**
 * 
 * @ClassName: Phone
 * @Description: 抽象产品角色-手机
 * @author admin
 * @date 2016年12月10日 上午11:40:26
 * @version V1.0
 */
public abstract class Phone {

}
/**
 * 
 * @ClassName: Earphone
 * @Description: 抽象产品角色-耳机
 * @author admin
 * @date 2016年12月10日 上午11:41:06
 * @version V1.0
 */
public abstract class Earphone {

}
/**
 * 
 * @ClassName: AscendSeriesPhone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:42:11
 * @version V1.0
 */
public class AscendSeriesPhone extends Phone {

	public AscendSeriesPhone(String str) {

		System.out.println(str);
	}
}
/**
 * 
 * @ClassName: HonourSeriesPhone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:15:42
 * @version V1.0
 */
public class HonourSeriesPhone extends Phone {
	
	public HonourSeriesPhone() {

		System.out.println("创造Honour系列的华为品牌手机");
	}
}
/**
 * 
 * @ClassName: GoldSeriesPhone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:15:58
 * @version V1.0
 */
public class GoldSeriesPhone extends Phone {
	
	public GoldSeriesPhone() {

		System.out.println("创造Gold系列的华为品牌手机");
	}
}
/**
 * 
 * @ClassName: AscendSeriesEarphone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:43:39
 * @version V1.0
 */
public class AscendSeriesEarphone extends Earphone {

	public AscendSeriesEarphone(String str) {

		System.out.println(str);
	}
}
/**
 * 
 * @ClassName: AscendSeriesEarphone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:43:39
 * @version V1.0
 */
public class HonourSeriesEarphone extends Earphone {

	public HonourSeriesEarphone() {

		System.out.println("创造Honour系列的耳机");
	}
}
/**
 * 
 * @ClassName: AscendSeriesEarphone
 * @Description: 具体产品角色
 * @author admin
 * @date 2016年12月10日 上午11:43:39
 * @version V1.0
 */
public class GoldSeriesEarphone extends Earphone {

	public GoldSeriesEarphone() {

		System.out.println("创造Gold系列的耳机");
	}
}
工厂相关角色

/**
 * 
 * @ClassName: IProductFactory
 * @Description: 抽象工厂类
 * @author admin
 * @date 2016年12月10日 上午11:45:46
 * @version V1.0
 */
public interface IProductFactory {

	public abstract Phone createPhone();
	
	public abstract Earphone createEarphone();
}
/**
 * 
 * @ClassName: ProductFactoryOne
 * @Description: 具体工厂角色
 * @author admin
 * @date 2016年12月10日 上午11:47:42
 * @version V1.0
 */
public class ProductFactoryOne implements IProductFactory {

	@Override
	public Phone createPhone() {
		
		return new AscendSeriesPhone("创造第一代Ascend系列的华为品牌手机");
	}

	@Override
	public Earphone createEarphone() {
		
		return new AscendSeriesEarphone("创造第一代Ascend系列的耳机");
	}
}
/**
 * 
 * @ClassName: ProductFactoryTwo
 * @Description: 具体工厂角色
 * @author admin
 * @date 2016年12月10日 上午11:47:42
 * @version V1.0
 */
public class ProductFactoryTwo implements IProductFactory {

	@Override
	public Phone createPhone() {
		
		return new AscendSeriesPhone("创造第二代Ascend系列的华为品牌手机");
	}

	@Override
	public Earphone createEarphone() {
		
		return new AscendSeriesEarphone("创造第二代Ascend系列的耳机");
	}
}
客户端

/**
 * 
 * @ClassName: Customer
 * @Description: 客户端
 * @author admin
 * @date 2016年12月10日 上午11:53:07
 * @version V1.0
 */
public class Customer {

	public static void main(String[] args) {
		
		//创造第一代手机和耳机
		IProductFactory productFactory = new ProductFactoryOne();
		productFactory.createPhone();
		productFactory.createEarphone();
		
		//创造第二代手机和耳机
		productFactory = new ProductFactoryTwo();
		productFactory.createPhone();
		productFactory.createEarphone();
	}
}
3)分析:从抽象工厂方法模式的代码可以看到,它与工厂方法模式的主要区别就是需要创建的对象的复杂程度上,抽象工厂方法模式不仅创建了工厂方法模式可以创建的具体产品角色,还可以创建与之相关联的具体产品角色;同时抽象工厂方法模式可以创建多个具体产品角色的实例。而且抽象工厂方法模式是三个分类里边最为抽象,最具一般性的模式。

未完待续。



















  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值