创造类模式:工厂方法模式VS建造者模式。

工厂方法模式注重的是整体对象的创建方法,而建造者模式注重的是部件构件的过程,旨在通过一步一步地精确构造创建出一个复杂的对象。我们举个简单例子来说明两者的差异,如要制造一个超人,如果使用工厂方法模式,直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人;而如果使用建造者模式,则需要组装手、头、脚、躯干等部分,然后再把内裤外穿,于是一个超人就产生了。

按工厂方法建造超人

首先,按照工厂方法模式创建出一个超人,按照年龄把超人分为两种类型:成年超人和未成年超人。这是一个非常正宗的工厂方法模式,定义一个产品的接口,然后再定义两个实现,通过超人制造工厂制造超人。想想看我们对超人最大印象是什么?当然是他的超能力,我们以specialTalent方法来代表,先看抽象产品类,如下所示。

public interface ISuperMan {
	/**
	 * 每个超人都有特殊技能
	 */
	void specialTalent();
}

产品的接口定义好了,我们再来看具体的产品。先看成年超人,很简单,如下所示。

public class AdultSuperMan implements ISuperMan {

	@Override
	public void specialTalent() {
		System.out.println("超人力大无穷");
	}

}

未成年超人的代码如下所示。

public class ChildSuperMan implements ISuperMan {

	@Override
	public void specialTalent() {
		System.out.println("小超人的能力是刀枪不入、快速运动");
	}

}

产品都具备,那我们编写一个工厂类,其意图就是生产超人,具体是成年超人还是未成年超人,则由客户端决定,如下所示。

public class SuperManFactory {
	/**
	 * 定义一个生产超人的工厂
	 * 
	 * @param type
	 * @return
	 */
	public static ISuperMan createSuperMan(String type) {
		// 根据输入参数产生不同的超人
		if ("adult".equalsIgnoreCase(type)) {
			// 生产成人超人
			return new AdultSuperMan();
		} else if ("child".equalsIgnoreCase(type)) {
			// 生成未成年超人
			return new ChildSuperMan();
		} else {
			return null;
		}
	}
}

产品有了,工厂类也有了,剩下的工厂就是开始生产超人。这也非常简单,如下所示。

public class Client {
	/**
	 * 场景类
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		// 生产一个成年超人
		ISuperMan adultSuperMan = SuperManFactory.createSuperMan("adult");
		// 展示一下超人的技能
		adultSuperMan.specialTalent();
	}
}

建立了一个超人生产工厂,年复一年的生产超人,对于具体生产出的产品,不管是成年超人还是未成年超人,都是一个模样:深蓝色紧身衣、胸前S标记、内裤外穿,没有特殊的地方。但是我们的目的达到了——生产出超人,拯救全人类,这就是我们的意图。具体怎么生产、怎么组装,这不是工厂方法模式要考虑的,也就是说,工厂模式关注的是一个产品整体,生产出的产品应该具有相似的功能和架构。

注意:通过工厂方法模式生产出对象,然后由客户端进行对象的其他操作,但是并不代表所有生产出的对象都必须具有相同的状态和行为,他是由产品所决定。

按建造者模式建造超人

我们再来看看建造者模式是如何生产超人的,我们在抽象建造者上使用了模板方法模式,每一个建造者都必须返回一个产品,但是产品是如何制造的,则由各个建造者自己负责。我们来看看程序,先看产品类,如下所示。

public class SuperMan {
	// 超人的躯体
	private String body;
	// 超人的特殊技能
	private String specialTalent;
	// 超人的标志
	private String specialSymbol;

	public String getBody() {
		return body;
	}

	public void setBody(String body) {
		this.body = body;
	}

	public String getSpecialTalent() {
		return specialTalent;
	}

	public void setSpecialTalent(String specialTalent) {
		this.specialTalent = specialTalent;
	}

	public String getSpecialSymbol() {
		return specialSymbol;
	}

	public void setSpecialSymbol(String specialSymbol) {
		this.specialSymbol = specialSymbol;
	}

}

超人这个产品是由三部分组成:躯体、特殊技能、身份标记,这就类似于电子产品,首先生产出一个固件,然后再安装一个灵魂(软件驱动),最后再打上产品标签。完事了!一个崭新的产品就诞生了!我们的超人也是这样生产的,先生产一个普通的躯体,然后注入特殊技能,最后打上S标签,一个超人生产完毕。我们再来看一下建造者的抽象定义,如下所示。

public abstract class Builder {
	// 定义一个超人的应用
	protected final SuperMan superMan = new SuperMan();

	/**
	 * 构造出超人躯体
	 * 
	 * @param body
	 */
	public void setBody(String body) {
		this.superMan.setBody(body);
	}

	/**
	 * 构建出超人的特殊技能
	 * 
	 * @param st
	 */
	public void setSpecialTalent(String st) {
		this.superMan.setSpecialTalent(st);
	}

	/**
	 * 购机拿出超人的特殊标记
	 * 
	 * @param ss
	 */
	public void setSpecialSymbol(String ss) {
		this.superMan.setSpecialSymbol(ss);
	}

	/**
	 * 构建出一个完整的超人
	 * 
	 * @return
	 */
	public abstract SuperMan getSuperMan();
}

一个典型的模板方法模式,超人的各个部件(躯体、灵魂、标志)都准备好了,具体怎么组装则是由实现类来决定。我们先来看成年超人,如下所示。

public class AdultSuperManBuilder extends Builder {

	@Override
	public SuperMan getSuperMan() {
		super.setBody("强壮的躯体");
		super.setSpecialTalent("会飞行");
		super.setSpecialSymbol("胸前带S标记");
		return super.superMan;
	}

}

怎么回事?在这里怎么把模板方法模式迁移到建造者了?设计模式只是提供了一个解决问题的意图:复杂对象的构件与他的表示分离,而没有具体定出一个设计模式必须是这样的实现,必须是这样的代码,灵活运用模式才是其根本,别学死板了。
我们继续看未成年超人的建造者,如下所示。

public class ChildSuperManBuilder extends Builder {

	@Override
	public SuperMan getSuperMan() {
		super.setBody("强壮的躯体");
		super.setSpecialTalent("刀枪不入");
		super.setSpecialSymbol("胸前带小S标记");
		return super.superMan;
	}

}

大家注意看我们这两个具体的建造者,他们都关注了产品的各个部分,在某些应用场景下甚至会关心产品的构件顺序,即使是相同的部件,装配顺序不同,产生的结果也不同,这也正是建造者模式的意图:通过不同的部件、不同装备产生不同的复杂对象。我们再来看导演类,如下所示。

public class Director {
	// 两个建造者的应用
	private static Builder adultBuilder = new AdultSuperManBuilder();
	// 未成年人的建造者
	private static Builder childBuilder = new ChildSuperManBuilder();

	/**
	 * 建造一个成年、会飞行的超人
	 * 
	 * @return
	 */
	public static SuperMan getAdultSuperMan() {
		return adultBuilder.getSuperMan();
	}

	/**
	 * 建造一个未成年、刀枪不入的超人
	 * 
	 * @return
	 */
	public static SuperMan getChildSuperMan() {
		return childBuilder.getSuperMan();
	}
}

这很简单,不多说了!看看场景类是如何调用的,如下所示。

public class Client {
	public static void main(String[] args) {
		// 建造一个成年超人
		SuperMan adultSuperMan = Director.getAdultSuperMan();
		// 展示一下超人的信息
		System.out.println(adultSuperMan.getSpecialTalent());
	}
}

这个场景类的写法与工厂方法模式是相同的,但是你可以看到,在建立超人的过程中,建造者必须关注超人的各个部件,而工厂方法模式则只关注超人的整体,这就是两者的区别。

最佳实践

工厂方法模式和建造者模式都属于对象创建类模式,都用来创建类的对象。但他们之间的区别还是比较明显的。

  • 意图不同

在工厂方法模式里,我们关注的是一个产品整体,如超人整体,无须关心产品的各部分是如何创建出来的;但在建造者模式中,一个具体产品的产生是依赖各个部件的产生以及装配顺序,他关注的是“由零件一件一件的组装出产品对象”。简单的说,工厂模式是一个对象创建的粗线条应用,建造者模式则是通过细线条勾勒出一个复杂对象,关注的是产品组成部分的创建过程。

  • 产品的复杂度不同

工厂方法模式创建的产品一般都是单一性质产品,如成年超人,都是一个模样,而建造者模式创建的则是一个复合产品,他由各个部件复合而成,部件不同产品对象当然不同。这不是说工厂方法模式创建的对象简单,而是指他们的粒度大小不同。一般来说,工厂方法模式的对象粒度比较粗,建造者模式的产品对象粒度比较细。

两者的区别有了,那在具体的应用中,我们该如何选择呢?是用工厂方法模式来创建对象,还是用建造者模式来创建对象,这完全取决于我们在做系统设计时的意图,如果需要详细关注一个产品部件的生产、安装步骤,则选择建造者,否则选择工厂方法模式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值