zoukankan      html  css  js  c++  java
  • 【JAVA设计模式】外观模式(Facade Pattern)

    一  定义

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


    二  案例

    一个子系统中拥有3个模块。每一个模块中都有3个方法。当中一个为client调用方法,其它两个则为各子模块间互相调用方法。此时有例如以下需求,client为完毕功能。须要组合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,文末会给出地址。
    client调用例如以下:
    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();
    	}
    }
    
    相信非常easy能够写出这种代码。

    细致想想能够发现,假设这样写。会存在例如以下问题:

    1. 代码耦合度太高,client与子系统中各模块都有关联。一旦子系统有什么更改,会涉及到client的改动。
    2. 对client学习成本太高。client须要学习各个模块中每一个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();
    	}
    }
    
    这样一来。client仅仅要与外观类打交道就可以,从而更好地实现了client和子系统各模块的耦合性。

    使用外观的目的: 不是给子系统加入新的功能接口,而是让外部降低对子系统内部多个模块的直接交互。松散耦合,从而可以让外部更简单地使用子系统。

    当然有时你会有这种需求,client可能仅仅须要调用两个模块就可以,那么现有的外观模式就无法使用了,仅仅好绕开外观类。直接找各模块进行调用。此外,你是否发现。我的ABC模块里面除了有供外部调用的方法外。还有各模块间互相调用的方法,这些方法本不须要client了解。暴露了过多内部细节。会让client产生疑惑,这就是“接口污染  。要解决问题,我们能够将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();
    	}
    }
    
    这样以后,就对client降低了模块内部方法的暴露。

    五  总结

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

  • 相关阅读:
    IP协议
    ARP协议分析
    总结struts2 iterator status的用法
    ibatis常用16条SQL语句
    Maven 项目debug调试时报Source not found.异常
    java面试题链接
    Android开发技巧一--weight属性实现视图的居中(半)显示
    Android中事件传递机制的总结
    Fragment的数据传递
    Android PopupWindow使用之地区、学校选择二级联动
  • 原文地址:https://www.cnblogs.com/yangykaifa/p/7290448.html
Copyright © 2011-2022 走看看