对 工厂模式与建造者模式 的个人理解,以及结合运用

学习了一段时间设计模式,就想分享一下自己的理解, 欢迎大家多多指点,指出不足之处哈

个人理解,工厂模式用于处理 如何获取实例对象 问题,建造者模式用于处理如何建造实例对象 问题(好像是废话。。。)。两者应该可以结合起来,下面将以商店售卖手机这场景来描述。


工厂模式

简单工厂模式-工厂方法模式


简单工厂模式由SimplePhoneFactory,集中获取不同的手机实例对象。

工厂方法模式由PhoneFactory的两个实现,分别获取不同的手机实例对象。

下面贴上代码,主要关注工厂类。

public abstract class Phone {
	/**
	 * 品牌
	 */
	protected String brand;
	
	/**
	 * 操作系统
	 */
	protected String os;

	/**
	 * 充电
	 */
	public abstract void charge();

	//GET SET方法...
}

public class ApplePhone extends Phone {
	@Override
	public void charge() {
		System.out.println("普通充电");
	}
}

public class SonyPhone extends Phone {
	@Override
	public void charge() {
		System.out.println("快充");
	}
}

public class SimplePhoneFactory {
	public static Phone getPhone(int brand) {
		if (brand == 0) {
			ApplePhone applePhone = new ApplePhone();
			applePhone.setBrand("Apple");
			return applePhone;
		}

		SonyPhone sonyPhone = new SonyPhone();
		sonyPhone.setBrand("Sony");
		return sonyPhone;
	}
}

public interface PhoneFactory {
	Phone getPhone();
}

public class SonyPhoneFactory implements PhoneFactory {
	public SonyPhone getPhone() {
		SonyPhone sonyPhone = new SonyPhone();
		sonyPhone.setBrand("Sony");
		return sonyPhone;
	}
}

public class ApplePhoneFactory implements PhoneFactory {
	public ApplePhone getPhone() {
		ApplePhone applePhone = new ApplePhone();
		applePhone.setBrand("Apple");
		return applePhone;
	}
}

public class StoreA {
	private int brand;

	public StoreA(int brand) {
		super();
		this.brand = brand;
	}

	/**
	 * 补充手机
	 */
	public void supplyPhone() {
		Phone phone = SimplePhoneFactory.getPhone(brand);
		// 补充手机逻辑...
		System.out.println("补充" + phone.getBrand() + "手机完成");
	}

	public static void main(String[] args) {
		StoreA storeA = new StoreA(0);
		storeA.supplyPhone();
	}
}

public class StoreB {
	private PhoneFactory phoneFactory;

	public StoreB(PhoneFactory phoneFactory) {
		super();
		this.phoneFactory = phoneFactory;
	}

	/**
	 * 补充手机
	 */
	public void supplyPhone() {
		Phone phone = phoneFactory.getPhone();
		// 补充手机逻辑...
		System.out.println("补充" + phone.getBrand() + "手机完成");
	}

	public static void main(String[] args) {
		StoreB storeB = new StoreB(new SonyPhoneFactory());
		storeB.supplyPhone();
	}
}


当要新增其它品牌的手机时,

简单工厂模式的SimplePhoneFactory类需要修改getPhone方法代码

工厂方法模式只需增加PhoneFactory的实现即可


小结:一类产品有多种不同实例对象(本例的手机,有不同品牌),当新增一种实例对象时(新增一个品牌的手机),工厂方法模式符合 对扩展开放,对修改封闭原则。

方法工厂模式-抽象工厂模式:增加一类产品:耳机,来方便对比。


接下来继续贴上代码,注意StoreC、StoreD的main方法。

public abstract class Headset {
	/**
	 * 品牌
	 */
	protected String brand;

	abstract void play();

	public String getBrand() {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}
}

public class AppleHeadset extends Headset {
	@Override
	void play() {
		// Apple 耳机播放逻辑 ...
		System.out.println("Apple 耳机播放完成");
	}
}

public class SonyHeadset extends Headset {
	@Override
	void play() {
		// Sony 耳机播放逻辑...
		System.out.println("Sony 耳机播放完成");
	}
}

public interface HeadsetFactory {
	Headset getHeadset();
}

public class SonyHeadsetFactory implements HeadsetFactory {
	public SonyHeadset getHeadset() {
		SonyHeadset sonyHeadset = new SonyHeadset();
		sonyHeadset.setBrand("Sony");
		return sonyHeadset;
	}
}

public class AppleHeadsetFactory implements HeadsetFactory {
	public AppleHeadset getHeadset() {
		AppleHeadset appleHeadset = new AppleHeadset();
		appleHeadset.setBrand("Apple");
		return appleHeadset;
	}
}

public interface Factory {
	Phone getPhone();

	Headset getHeadset();
}

public class AppleFactory implements Factory {
	public ApplePhone getPhone() {
		ApplePhone applePhone = new ApplePhone();
		applePhone.setBrand("Apple");
		return applePhone;
	}

	public AppleHeadset getHeadset() {
		AppleHeadset appleHeadset = new AppleHeadset();
		appleHeadset.setBrand("Apple");
		return appleHeadset;
	}
}

public class SonyFactory implements Factory {
	public SonyPhone getPhone() {
		SonyPhone sonyPhone = new SonyPhone();
		sonyPhone.setBrand("Sony");
		return sonyPhone;
	}

	public SonyHeadset getHeadset() {
		SonyHeadset sonyHeadset = new SonyHeadset();
		sonyHeadset.setBrand("Sony");
		return sonyHeadset;
	}
}

public class StoreC {
	private PhoneFactory phoneFactory;
	private HeadsetFactory headsetFactory;

	public StoreC(PhoneFactory phoneFactory, HeadsetFactory headsetFactory) {
		super();
		this.phoneFactory = phoneFactory;
		this.headsetFactory = headsetFactory;
	}

	/**
	 * 补充手机
	 */
	public void supplyPhone() {
		Phone phone = phoneFactory.getPhone();
		// 补充手机逻辑...
		System.out.println("补充" + phone.getBrand() + "手机完成");
	}

	/**
	 * 补充耳机
	 */
	public void supplyHeadset() {
		Headset headset = headsetFactory.getHeadset();
		// 补充耳机逻辑...
		System.out.println("补充" + headset.getBrand() + "耳机完成");
	}

	public static void main(String[] args) {
		StoreC storeD = new StoreC(new SonyPhoneFactory(), new SonyHeadsetFactory());
		storeD.supplyPhone();
		storeD.supplyHeadset();
	}
}

public class StoreD {
	private Factory factory;

	public StoreD(Factory factory) {
		super();
		this.factory = factory;
	}

	/**
	 * 补充手机
	 */
	public void supplyPhone() {
		Phone phone = factory.getPhone();
		// 补充手机逻辑...
		System.out.println("补充" + phone.getBrand() + "手机完成");
	}

	/**
	 * 补充耳机
	 */
	public void supplyHeadset() {
		Headset headset = factory.getHeadset();
		// 补充耳机逻辑...
		System.out.println("补充" + headset.getBrand() + "耳机完成");
	}
	
	public static void main(String[] args) {
		StoreD storeC = new StoreD(new SonyFactory());
		storeC.supplyPhone();
		storeC.supplyHeadset();
	}
}

从代码看,如果要从StoreC,StoreD中,选一个来实例化不同的专卖店,

抽象工厂中的StoreD更适合,只要在构造方法那传入不同的单个Factory,即可获得不同的专卖店。

而工厂方法中的StoreC,如果现在有耳机、手机、电脑、电视等等,那用StoreC实例化每个店,都得传入很多Factory,且得注意这些Factory都是同一品牌的。


小结:多类产品分别有多种不同实例对象(本例的手机,耳机都分别有不同品牌),而跨类别的实例对象有联系(本例的联系是同一品牌),暂且称有联系的那些实例对象为同一族。那抽象工厂模式可以让产品用户更方便获取同一族的产品。


疑问:如果产品用户没有获取同一族产品这需求,那工厂方法模式优点在哪?

我猜,如果不同族的产品线差异很大(如新增电脑,电视这两类产品,但Apple只有电脑,Sony只有电视),抽象工厂模式会产生很多无意义代码。

那抽象工厂模式的 AppleFactory的getTV,SonyFactory的getPC 就得返回null或者其它处理。

而工厂方法模式,只要按需新增ApplePCFactory,SonyTVFactory等。

工厂方法模式-建造者模式:





上面两个类图好像似,完全看不出建造者模式的必要。再看看结合建造者模式的工厂方法模式的类图:



呃。。。这类图太复杂了,还不如直接对着代码说来得方便。主要关注那几行作了记号(<<<<<<<<<<)的代码。

public interface PhoneBuilder {
	/**
	 * 刻铭牌
	 */
	void buildBrand();
	
	/**
	 * 安装系统
	 */
	void buildOs();

	Phone getResult();
}

public class ApplePhoneBuilder implements PhoneBuilder {
	private ApplePhone applePhone = new ApplePhone();

	public void buildBrand() {
		applePhone.setBrand("Apple");
	}

	public void buildOs() {
		applePhone.setOs("IOS");
	}
	
	public Phone getResult() {
		return applePhone;
	}
}

public class SonyPhoneBuilder implements PhoneBuilder {
	private SonyPhone sonyPhone = new SonyPhone();

	public void buildBrand() {
		sonyPhone.setBrand("Sony");
	}

	public void buildOs() {
		sonyPhone.setOs("Android");
	}

	public Phone getResult() {
		return sonyPhone;
	}
}

public interface PhoneFactory {
	Phone getPhone();
}

//普通的工厂方法模式工厂类
public class SonyPhoneFactory implements PhoneFactory {
	public SonyPhone getPhone() {
		SonyPhone sonyPhone = new SonyPhone();
		sonyPhone.setBrand("Sony");<<<<<<<<<<<<<<<<<<
		sonyPhone.setOs("Android");<<<<<<<<<<<<<<<<<<
		return sonyPhone;
	}
}

public class ApplePhoneFactory implements PhoneFactory {
	public ApplePhone getPhone() {
		ApplePhone applePhone = new ApplePhone();
		applePhone.setBrand("Apple");<<<<<<<<<<<<<<<<<<
		applePhone.setOs("IOS");<<<<<<<<<<<<<<<<<<
		return applePhone;
	}
}

//结合建造者模式的工厂类
public class PhoneDirector {
	public Phone construct(PhoneBuilder builder) {
		builder.buildBrand();<<<<<<<<<<<<<<<<<<
		builder.buildOs();<<<<<<<<<<<<<<<<<<
		return builder.getResult();
	}
}

public class ApplePhoneFactory implements PhoneFactory {
	private PhoneDirector director = new PhoneDirector();

	public ApplePhone getPhone() {
		ApplePhoneBuilder builder = new ApplePhoneBuilder();
		return (ApplePhone) director.construct(builder);
	}
}

public class SonyPhoneFactory implements PhoneFactory {
	private PhoneDirector director = new PhoneDirector();

	public SonyPhone getPhone() {
		SonyPhoneBuilder builder = new SonyPhoneBuilder();
		return (SonyPhone) director.construct(builder);
	}
}


虽然类图那么复杂,但从代码看,还是很容易看出建造者模式的作用。

普通的工厂方法模式中,同一类产品中不同实例对象的建造过程(SonyPhoneFactory,ApplePhoneFactory中作记号的代码),十分相似。那是不是可以抽出来,从而做到代码复用。

再看看结合了建造者模式的工厂类,就会明白建造者模式就是把建造过程抽到了导演类中(PhoneDirector中作记号的代码)。之所以能够这样,多亏了前面的多个Builder类。


又有疑问了,为了复用重复代码,却要新增那么多类,是不是有点得不偿失?

我猜,建造者模式抽取建造过程,不是为了减少代码量,而是为了把建造顺序统一到一个地方!以后一旦要修改建造顺序,也只需要修改导演类即可!

至于 抽象工厂模式-建造者模式,由于原理相似,就不哆嗦了。


小结:当一类产品中不同实例对象的建造过程相似,且未来很有可能要修改建造顺序的话,那建造者模式可以处理这种情况。


总结:从 普通的工厂方法模式 到 结合建造者模式的工厂方法模式,对产品用户(Store类)没有影响。所以对于产品用户来说,是否用建造者模式是不知情的,因为产品用户只关心产品的获取。所以正如开头所说,工厂模式用于处理 如何获取实例对象 问题,建造者模式用于处理 如何建造实例对象 问题。


下篇文章打算在 工厂方法模式-建造者模式 基础上,再结合 桥接模式,感觉这三个模式的结合运用,在实际中很常见。到时那类图想想都好恐怖。。。


  • 12
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值