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

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

桥接模式:以商店与手机为例子来描述,先从简单的依赖关系说起


public interface Phone {
	/** 充电 **/
	void charge();

	/** 解锁 **/
	void unlock();
}

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

	public void unlock() {
		System.out.println("指纹解锁");
	}
}

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

	public void unlock() {
		System.out.println("面部解锁");
	}
}

public class Store {
	/**
	 * 补充手机
	 */
	public void supplyPhone() {
		Phone phone = new SonyPhone();
		// 补充手机逻辑...
		System.out.println("补充手机完成");
	}
}

上面这类图很简单,就是Phone接口有两个实现。Store只依赖Phone接口,不依赖具体实现,这样方便Store更换手机。

如果现在,想增加个实现,NokiaPhone,而且有以下要求:

1、NokiaPhone的charge方法,要跟SonyPhone的一样,同样是快充。

2、NokiaPhone的unlock方法,要跟ApplePhone的一样,同样是指纹解锁。

看到第1点,就让人毫不犹豫想到,可以让NokiaPhone继承SonyPhone。

接着看到2点,就发现 NokiaPhone继承SonyPhone 带来的问题了。NokiaPhone无法通过继承ApplePhone来重用指纹解锁(不能继承多个类),只能硬生生的复制ApplePhone的过来用。如下

public class NokiaPhone extends SonyPhone {
	public void unlock() {
		System.out.println("指纹解锁");
	}
}

由此可见,继承也会出现代码不能复用的问题

除此之外,若现在NokiaPhone想增加个功能 照相(takePicture)。

由于Store依赖的是Phone,所以Phone得加takePicture方法

public interface Phone {
	/** 充电 **/
	void charge();

	/** 解锁 **/
	void unlock();

	/** 照相 **/
	void takePicture();
}

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

	public void unlock() {
		System.out.println("指纹解锁");
	}

	public void takePicture() {
		// 空实现
		return;
	}
}

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

	public void unlock() {
		System.out.println("面部解锁");
	}

	public void takePicture() {
		// 空实现
		return;
	}
}

public class NokiaPhone extends SonyPhone {
	public void unlock() {
		System.out.println("指纹解锁");
	}

	public void takePicture() {
		System.out.println("双摄");
	}
}
从代码看,一旦其中一个实现增加特有的功能,其它的实现都得修改,增加很多空实现的代码。

小结:继承,不能很好解决代码重用,而且不方便扩展。

再看回原来的SonyPhone、ApplePhone实现的方法,可以归类得出

charge: 普通充电,快充

unlock: 指纹解锁,面部解锁

之后新增的NokiaPhone相当于从上面每个功能,分别抽取所需的实现来组合而成。


这样有没感觉,若将 普通充电,快充,指纹解锁,面部解锁 分别放到不同的类,然后只要将按需set到NokiaPhone中即可。

事实上桥接模式,就类似这思路。


大家应该发现,这类图跟大家经常看到的不同,Abstraction缺少了个子类RefineAbstraction。由于本小白一直想不通RefineAbstraction的作用,所以也想通过这文章,希望各位大神能拔刀相助。

下面根据本例画上相应的类图


public interface Locker {
	void unlock();
}

public class FaceLocker implements Locker {
	public void unlock() {
		System.out.println("指纹解锁");
	}
}

public class FingerprintLocker implements Locker {
	public void unlock() {
		System.out.println("面部解锁");
	}
}

public interface Charger {
	void charge();
}

public class QuickCharger implements Charger {
	public void charge() {
		System.out.println("普通充电");
	}
}

public class SimpleCharger implements Charger {
	public void charge() {
		System.out.println("快充");
	}
}

public class Phone {
	private Charger charger;
	private Locker locker;

	public void charge() {
		if (charger == null) {
			return;
		}

		charger.charge();
	}

	public void unlock() {
		if (locker == null) {
			return;
		}

		locker.unlock();
	}

	public void setCharger(Charger charger) {
		this.charger = charger;
	}

	public void setLocker(Locker locker) {
		this.locker = locker;
	}
}

public class Store {
	/**
	 * 补充手机
	 */
	public void supplyPhone() {
		Phone phone = getNokiaPhone();
		// 补充手机逻辑...
		System.out.println("补充手机完成");
	}
	
	private Phone getSonyPhone(){
		Phone phone = new Phone();
		phone.setCharger(new QuickCharger());
		phone.setLocker(new FaceLocker());
		return phone;
	}
	
	private Phone getApplePhone(){
		Phone phone = new Phone();
		phone.setCharger(new SimpleCharger());
		phone.setLocker(new FingerprintLocker());
		return phone;
	}
	
	private Phone getNokiaPhone(){
		Phone phone = new Phone();
		phone.setCharger(new QuickCharger());
		phone.setLocker(new FingerprintLocker());
		return phone;
	}
}


用了桥接模式的话,Store就可以随意组合出所需的手机种类。

大家可能问,用户类Store要是更换其它种类手机,就得修改代码,不科学呀。

这问题就牵涉到 如何获取实例对象 问题,桥接模式解决的只是如何处理实例对象依赖 问题。(后面将提到如何结合 工厂方法模式,建造者模式 来方便获取不同的手机)

此时若新增 照相功能(takePicture)

public interface Camera {
	void takePicture();
}

public class DoubleCamera implements Camera {
	public void takePicture() {
		System.out.println("双摄");
	}
}

///
public class Phone {
	private Charger charger;
	private Locker locker;
	private Camera camera;

	public void charge() {
		if (this.charger == null) {
			return;
		}

		this.charger.charge();
	}

	public void unlock() {
		if (locker == null) {
			return;
		}

		this.locker.unlock();
	}

	public void takePicture() {
		if (this.camera == null) {
			return;
		}
		this.camera.takePicture();
	}

	public void setCharger(Charger charger) {
		this.charger = charger;
	}

	public void setLocker(Locker locker) {
		this.locker = locker;
	}

	public void setCamera(Camera camera) {
		this.camera = camera;
	}
}
///
public class Store {
	/**
	 * 补充手机
	 */
	public void supplyPhone() {
		Phone phone = getNokiaPhone();
		// 补充手机逻辑...
		System.out.println("补充手机完成");
	}
	
	private Phone getSonyPhone(){
		Phone phone = new Phone();
		phone.setCharger(new QuickCharger());
		phone.setLocker(new FaceLocker());
		return phone;
	}
	
	private Phone getApplePhone(){
		Phone phone = new Phone();
		phone.setCharger(new SimpleCharger());
		phone.setLocker(new FingerprintLocker());
		return phone;
	}
	
	private Phone getNokiaPhone(){
		Phone phone = new Phone();
		phone.setCharger(new QuickCharger());
		phone.setLocker(new FingerprintLocker());
		phone.setCamera(new DoubleCamera());
		return phone;
	}
}
此时Phone类只需增加一个takePicture方法,而且Store类,只修改了getNokiaPhone的方法(因为只有Nokia需要加照相功能),没有影响到其它方法。


小结:一类产品(本例的Phone)若多维上有多个不同实现(charge、camera、takePicture等方法都有多个实现)。此时若使用继承,会出现 代码难以重用、新增维度不方便 等问题,此时适合使用桥接模式

工厂方法模式-建造者模式-桥接模式:终于到高潮了,请先阅读 对 工厂模式与建造者模式 的个人理解,以及结合运用


public interface PhoneBuilder {
	void buildCharger();
	
	void buildLocker();

	Phone getResult();
}

public class ApplePhoneBuilder implements PhoneBuilder {
	private Phone phone = new Phone();

	public void buildCharger() {
		phone.setCharger(new SimpleCharger());
	}

	public void buildLocker() {
		phone.setLocker(new FingerprintLocker());
	}

	public Phone getResult() {
		return phone;
	}
}

public class SonyPhoneBuilder implements PhoneBuilder {
	private Phone phone = new Phone();

	public void buildCharger() {
		phone.setCharger(new QuickCharger());
	}

	public void buildLocker() {
		phone.setLocker(new FaceLocker());
	}

	public Phone getResult() {
		return phone;
	}
}
///
public class PhoneDirector {
	public Phone construct(PhoneBuilder builder) {
		builder.buildCharger();
		builder.buildLocker();
		return builder.getResult();
	}
}

public interface PhoneFactory {
	Phone getPhone();
}

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

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

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

	public Phone getPhone() {
		SonyPhoneBuilder builder = new SonyPhoneBuilder();
		return director.construct(builder);
	}
}
///
public class Store {
	private PhoneFactory phoneFactory;

	public Store(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();
	}
}


总结:

桥接模式将一类产品(本例的手机)的多维变化(charge、unlock方法各有不同实现),抽取成单独的类(Charger、Locker等实现)。

建造者模式的Builder角色负责从每个维度选取所需的实现类

工厂类,最后就变成只需将对应的Builder传入到Director里,调用Director开始按顺序建造。








猜你喜欢

转载自blog.csdn.net/MonkeyD5/article/details/73612791