【JAVA设计模式】外观模式(Facade Pattern)

一  定义

为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层的接口,这个接口使得这一子系统更加容易使用。

二  案例

一个子系统中拥有3个模块,每个模块中都有3个方法,其中一个为客户端调用方法,其他两个则为各子模块间互相调用方法。此时有如下需求,客户端为完成功能,需要组合3个模块中的方法才能实现功能。

三  未使用模式情况

/**
 * @Description A模块
 * @author jerry 
 * @date 2016年4月11日下午2:16:04
 */
public interface AModuleApi {
	public void a1();	//此方法主要用于外部调用
	public void a2();	//以下两方法主要用于子系统内部间调用
	public void a3();
}
/**
 * @Description A模块实现
 * @author jerry 
 * @date 2016年4月11日下午2:17:10
 */
public class AModuleImpl implements AModuleApi {

	@Override
	public void a1() {
		System.out.println("调用了A模块");
	}

	@Override
	public void a2() {
		//TODO 主要用于子模块间互相调用
	}

	@Override
	public void a3() {
		//TODO 主要用于子模块间互相调用
	}
}
/**
 * @Description B模块
 * @author jerry 
 * @date 2016年4月11日下午2:16:12
 */
public interface BModuleApi {
	public void b1();	//此方法主要用于外部调用
	public void b2();	//以下两方法主要用于子系统内部间调用
	public void b3();
}
/**
 * @Description B模块实现
 * @author jerry 
 * @date 2016年4月11日下午2:17:10
 */
public class BModuleImpl implements BModuleApi {

	@Override
	public void b1() {
		System.out.println("调用了B模块");
	}

	@Override
	public void b2() {
		//TODO 主要用于子模块间互相调用
	}

	@Override
	public void b3() {
		//TODO 主要用于子模块间互相调用
	}
}
同理,C模块也是如此,篇幅原因,这里不贴代码了,需要代码可以从我github下clone,文末会给出地址。
客户端调用如下:
public class Client {

	public static void main(String[] args) {
		AModuleApi a = new AModuleImpl();
		a.a1();
		BModuleApi b = new BModuleImpl();
		b.b1();
		CModuleApi c = new CModuleImpl();
		c.c1();
	}
}
相信很容易可以写出这样的代码。仔细想想可以发现,如果这样写,会存在如下问题:
  1. 代码耦合度太高,客户端与子系统中各模块都有关联。一旦子系统有什么更改,会涉及到客户端的修改。
  2. 对客户端学习成本太高,客户端需要学习各个模块中每个public方法,知道其什么含义后才能进行调用。


四  使用模式的情况

我们可以在 系统这端(即外观模式属于系统这端,若属于客户这端,仍然需要客户去了解每个模块每个方法意义,这样无任何意义。) 添加一个外观类,由外观类重组需要调用的方法,如下所示:
/**
 * @Description 外观类,通常设计成单例
 * @author jerry 
 * @date 2016年4月11日下午2:43:26
 */
public class Facade {
	private Facade(){}
	
	public static void test(){
		AModuleApi a = new AModuleImpl();
		a.a1();
		BModuleApi b = new BModuleImpl();
		b.b1();
		CModuleApi c = new CModuleImpl();
		c.c1();
	}
}
public class Client {

	public static void main(String[] args) {
//		AModuleApi a = new AModuleImpl();
//		a.a1();
//		BModuleApi b = new BModuleImpl();
//		b.b1();
//		CModuleApi c = new CModuleImpl();
//		c.c1();
		
		Facade.test();
	}
}
这样一来,客户端只要与外观类打交道即可,从而更好地实现了客户端和子系统各模块的耦合性。
使用外观的目的: 不是给子系统添加新的功能接口,而是让外部减少对子系统内部多个模块的直接交互,松散耦合,从而能够让外部更简单地使用子系统。

当然有时你会有这样的需求,客户端可能只需要调用两个模块即可,那么现有的外观模式就无法使用了,只好绕开外观类,直接找各模块进行调用。此外,你是否发现,我的ABC模块里面除了有供外部调用的方法外,还有各模块间互相调用的方法,这些方法本不需要客户端了解,暴露了过多内部细节,会让客户端产生疑惑,这就是“ 接口污染  ,要解决这个问题,我们可以将Facade类定义为接口,并对其实现,使用 工厂模式对其创建实例,如下所示:
public interface FacadeApi {
	public void a1();
	public void b1();
	public void c1();
	
	/**
	 * @Description 原有方法,将各模块方法组合调用
	 * @return void
	 * @throws 
	 */
	public void test();
}
/**
 * @Description 外观接口实现
 * @author jerry 
 * @date 2016年4月11日下午3:19:25
 */
public class FacadeImpl implements FacadeApi {

	@Override
	public void a1() {
		new AModuleImpl().a1();
	}

	@Override
	public void b1() {
		new BModuleImpl().b1();
	}

	@Override
	public void c1() {
		new CModuleImpl().c1();
	}

	@Override
	public void test() {
		a1();
		b1();
		c1();
	}
}
/**
 * @Description 外观接口实现
 * @author jerry 
 * @date 2016年4月11日下午3:19:25
 */
public class FacadeImpl implements FacadeApi {

	@Override
	public void a1() {
		new AModuleImpl().a1();
	}

	@Override
	public void b1() {
		new BModuleImpl().b1();
	}

	@Override
	public void c1() {
		new CModuleImpl().c1();
	}

	@Override
	public void test() {
		a1();
		b1();
		c1();
	}
}
public class Client {

	public static void main(String[] args) {
//		AModuleApi a = new AModuleImpl();
//		a.a1();
//		BModuleApi b = new BModuleImpl();
//		b.b1();
//		CModuleApi c = new CModuleImpl();
//		c.c1();
		
//		Facade.test();
		
		FacadeApi api = Factory.createFacade();
		api.test();
	}
}
这样以后,就对客户端减少了模块内部方法的暴露。

五  总结

外观模式的本质: 封装交互,简化调用
何时使用外观模式:
  1. 如果你希望为一个复杂的子系统提供一个简单接口
  2. 如果构建多层结构的系统,可以考虑使用外观模式,使用外观对象作为每层的入口,这样可以简化层间调用,可以降低耦合度。
------------------------------------------------------------------------------------------------------------------------------------------
Reference:《研磨设计模式》

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值