Java 设计模式 之 facade(外观)设计模式_亦山的博客-程序员宅基地

技术标签: Design Patterns  Java 设计模式  

概述:

      Facade模式要求一个子系统的外部与其内部的通信通过一个统一的Facade对象进行。Facade模式提供一个高层次的接口,使得子系统更易于使用。

      当子系统经过不断的演变,变得异常复杂时,这时候,为了让子系统能够工作,这就要求 客户端对子系统内的各个模块充分了解,才能使各个模块协同工作,达到业务目标。这样无疑增加了客户端的负担。这时候子系统可以为外部定义一个访问的接口,通过接口来完成内部的实现,客户端不需要考虑过多的东西。

案例:

    举一个例子,某君要开一个公司,他通过了解,得知注册一个公司大概要经过以下几个步骤:
     1.到工商部门申请一个公司名称;             //  commercialDepartment.applyCompanyName()
     2.去银行开一个验资账户 ;                       //  bank.createCheckAccount()
     3.准备材料,到工商部门拿营业执照;      // commercialDepartment.distributeBusinessLicense()
     4. 到公安局备案刻章;                            // policeBureau.distributeSeal()
     5. 到质检局办理组织机构代码证;         //  qualityInspectionBureau.distributeCertificate()
     6. 到税务部门办理税务登记 ;               //   taxBureau.registerTaxBusiness()
     7. 到银行开一个基本账户;                    //  bank.createBasicBank()
     8.到税务部门做税种鉴定;                     //  taxBureau.appraiseTaxType()

      上面的步骤相信大家都会被吓到:实在太麻烦了!开一个公司需要跑这么多个部门,有的部门还得跑多次,还有就是你要了解这个流程的每一步,对每个部门的具体职责要有很详细的了解,这样才能顺利完成。这个给我们一个非常强烈的感觉:政府机构太臃肿,做一件事怎么就这么难呢!!!!(呵呵,相信大家对这个深有体会吧)

      上述的这个流程:主要牵涉到政府的以下几个部门:工商部门、银行、公安局、质检局、税务部门;

       在代码里有类似下面的逻辑:对申请者而言,他要持有所有部门的引用,并且对部门的功能有较全面的了解,并且知道这些部门怎么协同工作的。这样无疑增加了额申请者的负担。

     

package com.lou.design.pattern.Facade;


public class Client {

	public  void applyRunCompany() {

		// 持有对各个部门的引用
		CommercialDepartment commercialDepartment = new CommercialDepartment();
		Bank bank = new Bank();
		PoliceBureau policeBureau = new PoliceBureau();
		TaxBureau taxBureau = new TaxBureau();
		QualityInspectionBureau qualityInspectionBureau = new QualityInspectionBureau();

		// 申请开公司
		System.out.println("------开始申请开公司........");
		
		commercialDepartment.applyCompanyName();          //1.到工商部门申请一个公司名称; 
	    
		bank.createCheckAccount();                         // 2.去银行开一个验资账户 ;                       //  
	    
		commercialDepartment.distributeBusinessLicense(); //3.准备材料,到工商部门拿营业执照;
	    
		policeBureau.distributeSeal();                    // 4. 到公安局备案刻章;
	    
		qualityInspectionBureau.distributeCertificate();   // 5. 到质检局办理组织机构代码证;
	    
		taxBureau.registerTaxBusiness();                   // 6. 到税务部门办理税务登记 ;
	    
		bank.createBasicBank();                           // 7. 到银行开一个基本账户;
	    
		taxBureau.appraiseTaxType();                       //8.到税务部门做税种鉴定; 
	    
		System.out.println("苍天啊,终于可以开公司了!!!");
	}
	
	public static void main(String[] args) {
		new Client().applyRunCompany();
	}
}


 

package com.lou.design.pattern.Facade;

public class Department {
	
}

class CommercialDepartment{
	//工商局其他功能 省略
	public void applyCompanyName()
	{
		System.out.println("工商局:申请一个公司名称。");
	}
	
	public void distributeBusinessLicense()
	{
		System.out.println("工商局:发放营业执照。");
	}
	
	//工商局其他功能 省略
}

class Bank{
	//银行其他功能 省略
	public void createCheckAccount()
	{
		System.out.println("银行:开一个验资账户。");
	}
	
	public void createBasicBank()
	{
		System.out.println("银行: 开一个基本账户。");
	}
	//银行其他功能 省略
}

class PoliceBureau{
	//其他功能 省略
	public void distributeSeal()
	{
		System.out.println("公安局:备案刻章。");
	}
	//其他功能 省略
}
class QualityInspectionBureau{
	//其他功能 省略
	public void distributeCertificate(){
		System.out.println("质检局:办理组织机构代码证。");
	}
	//其他功能 省略
}
class TaxBureau{
	//其他功能 省略
	public void registerTaxBusiness()
	{
		System.out.println("税务部门:税务登记。");
	}
	public void appraiseTaxType()
	{
		System.out.println("税务部门:税种鉴定。");
	}
	//其他功能 省略
}


程序运行结果:


            鉴于这一流程太过繁琐,有不少人跟政府反映,政府觉得,应该要对老百姓简化流程,给老百姓解决办事难的问题,所以开设了一个绿色通道,申请者只需要将相关的材料交给这个绿色通道,就可以办完开公司的手续了!(如下图所示)

           

    

像这样,政府对外公布一个绿色通道,只需要通过绿色通道提供的服务即可,不需要自己再到不同的部门去申请各式各样的请求了。

虽然说政府简化了申请者的流程,但是本来应该有的流程还是必不可少的,只不过是政府部门自己内部协调处理了。

以下是以上优化的代码展示:

package com.lou.design.pattern.Facade;


public class GreenChannel {

	public static void applyRunCompany() {
	    
		// 持有对各个部门的引用
		CommercialDepartment commercialDepartment = new CommercialDepartment();
		Bank bank = new Bank();
		PoliceBureau policeBureau = new PoliceBureau();
		TaxBureau taxBureau = new TaxBureau();
		QualityInspectionBureau qualityInspectionBureau = new QualityInspectionBureau();

		System.out.println("-----------您正在使用政府绿色通道-------------");
		commercialDepartment.applyCompanyName();          //1.到工商部门申请一个公司名称; 

	    bank.createCheckAccount();                         // 2.去银行开一个验资账户 ;                       //  

	    commercialDepartment.distributeBusinessLicense(); //3.准备材料,到工商部门拿营业执照;

	    policeBureau.distributeSeal();                    // 4. 到公安局备案刻章;

	    qualityInspectionBureau.distributeCertificate();   // 5. 到质检局办理组织机构代码证;

	    taxBureau.registerTaxBusiness();                   // 6. 到税务部门办理税务登记 ;

	    bank.createBasicBank();                           // 7. 到银行开一个基本账户;

	    taxBureau.appraiseTaxType();                       //8.到税务部门做税种鉴定; 

	    System.out.println("谢谢您使用政府绿色通道!");
	}
	
}
package com.lou.design.pattern.Facade;


public class Client {

	public  void applyRunCompany() {

     		GreenChannel.applyRunCompany();
	}
	
	public static void main(String[] args) {
		new Client().applyRunCompany();
	}
}

 

总结:

一般地,  假设 客户端Client ,和系统内的若干子系统:A,B,C,D…。 现在Client 要完成一项工作,需要A,B,C,D协调完成。

public class Client{

        public void doSomething()
        {
             A a = new A();
             B b = new B();
             C c = new C();
             D d = new D();
             
             A.doMethod1();
             B.doMethod2();
             C.doMethod3();
             D.doMethod4();
             // 再做其他的事情
        }

    }


像上面的Client完成doSomething() 所要需要执行四个子系统A,B,C,D的相关功能。这就要求Client对其子系统内部要相当的熟悉,知道其内部功能结构才可以。这样会增加Client的负担,整个子系统也显得臃肿和混乱。如果有更多的Client 想实现这样的功能,这样的代码还要重复敲多少遍啊。

现在可以为子系统增加一个接口,Client只需要通过这个接口,即可完成doSomething()的功能。

// 将子系统进行封装,给外界提供一个统一的界面接口,不需要Client对子系统要有高要求的了解。
    public class Facade{

        public void service()
        {
             A a = new A();
             B b = new B();
             C c = new C();
             D d = new D();
             
             A.doMethod1();
             B.doMethod2();
             C.doMethod3();
             D.doMethod4();
             // 再做其他的事情
        }
    }
    
    //调用子系统提供的门面
    public class Client{
        public void doSomething()
        {
            Facade facade = new Facade();
            facade.service();//门面提供的方法
        }

    }




 下面是 StarUML 提供的GoF 设计模式的帮助文档,本人做了粗糙的标注,以飨读者。

Facade (门面)

Purpose (目的)

  • Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
  • 为子系统的一系列接口提供一个统一的接口。门面模式定义了一个更高级别的接口,以使子系统更好地被使用。

Structure (组成结构)

       

  • Facade : knows which subsystem classes are responsible for a request. delegates client requests to appropriate subsystem objects.
  • 门面角色 : 了解可以处理此请求的子系统内的类。将客户(Client) 的请求代理给合适的子系统对象处理。
  • Subsystem Classes : implement subsystem functionality. handle work assigned by the Facade object. have no knowledge of the facade; that is, they keep no references to it.
  • 子系统类: 实现子系统的功能. 处理门面角色指派的工作。子系统类不知道门面角色的存在,即:它们没有持有对Facade的引用。

Interaction (交互)

  • Clients communicate with the subsystem by sending requests to Facade, which forwards them to the appropriate subsystem object(s). Although the subsystem objects perform the actual work, the facade may have to do work of its own to translate its interface to subsystem interfaces.
  • 客户(Client)通过给Facade发送请求、Facade将请求转发给合适的子系统对象的方式和子系统进行通信。虽然子系统对象完成真正的工作,但是facade 必须完成自己的工作:将自己的接口转换成子系统的接口。
  • Clients that use the facade don't have to access its subsystem objects directly.
  • 客户(Client)使用facade,不需要直接接触子系统对象。

Applications (应用)

  •  you want to provide a simple interface to a complex subsystem. Subsystems often get more complex as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the subsystem more reusable and easier to customize, but it also becomes harder to use for clients that don't need to customize it. A facade can provide a simple default view of the subsystem that is good enough for most clients. Only clients needing more customizability will need to look beyond the facade.
  •  当你希望为复杂的子系统提供一个简单的接口时。 随着子系统的演化而变得愈发复杂. 采用的大多数的设计模式, 将会产生越来越多和越小的类。这是的子系统有更好的重用性和更容易满足个性化需求,于此同时,这也使那些不需要定制它的用户 更难使用它。facade 可以为子系统提供一个简单的默认的视图,这个视图对于大多数的客户(Client)来说已经足够了。只有那些需要更多个性化需求的用户(Client)才需要不使用facade ,而直接接触子系统。
  • there are many dependencies between clients and the implementation classes of an abstraction. Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting subsystem independence and portability.
  • 当客户(client) 和抽象类的实现类之间有过多的依赖时。引入门面模式来将子系统从客户(Clients)和其他的子系统中解耦出来,这样就能够提高子系统的独立性和可移植性。

Consequences (结论)

  •  It shields clients from subsystem components, thereby reducing the number of objects that clients deal with and making the subsystem easier to use.
  •  将客户(Clients) 从众多的子系统组件中保护起来,这样,减少了客户(Clients) 和子系统交互的对象的数目,使子系统更好地被使用。
  • It promotes weak coupling between the subsystem and its clients. Often the components in a subsystem are strongly coupled. Weak coupling lets you vary the components of the subsystem without affecting its clients. Facades help layer a system and the dependencies between objects. They can eliminate complex or circular dependencies. This can be an important consequence when the client and the subsystem are implemented independently.
  • 加强了子系统和客户端(Client)之间的弱耦合。一般情况下子系统的组件之间有很强的耦合。弱耦合是我们可以在不影响客户端(Client)的情况下改变子系统中的组件。门面模式有助于系统和对象之间的依赖关系进行分层。它们可以消除复杂或者环形的依赖关系。(门面模式)是在对客户和子系统之间独立实现(的解决方案)中很重要的一个结论。
  • It doesn't prevent applications from using subsystem classes if they need to. Thus you can choose between ease of use and generality.
  • 门面模式并不会使程序在需要使用子系统类的时候无法使用。你可以在"容易使用"和"一般性"之间进行选择。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010349169/article/details/18843073

智能推荐

如何动态修改hololens Camera的位置和旋转角度_1386的博客-程序员宅基地

一、将HololensCamera对象,放到一个空的GameObject下,命名为HololensComponent.如:二、需要更改HololensCamera的位置和旋转角度的时候只需要更改HololensComponent的transform.position和transform.localEulerAngles便可如:GameObject.Find("Hol...

云服务器如何安装docker?_weix13138169001的博客-程序员宅基地

一、为什么要使用Docker?理由很简单,用了的人都说好用。在多系统的分布式项目中,往往传统的部署发包等操作,那是让每个上线的程序员恨的牙痒呀。通常都是通宵奋战,上生产解决各种部署发包问题。个人简单总结一下三点:1.部署简单且灵活,有独立的运行环境,避免了不必要的冲突。2.节省了资源开销3.类似于java, 打包一次各处部署运行。项目迁移灵活便捷。二、什么是docker呢?在讲之前,先来说说什么时容器?什么时虚拟机?看下图:简单解释一下,图左为容器,图右为虚拟机。Docker 属于 L

[leetcode]Python实现-350.两个数组的交集II_python350. 两个数组的交集_神不烦的博客-程序员宅基地

350.两个数组的交集II描述 给定两个数组,写一个方法来计算它们的交集。例如 给定 nums1 = [1, 2, 2, 1], nums2 = [2, 2], 返回 [2, 2].注意 输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。 我们可以不考虑输出结果的顺序。跟进 如果给定的数组已经排好序呢?你将如何优化你...

shared_from_this_shared_from_this 子类_Nphard999的博客-程序员宅基地

shared_from_this是基类enable_shared_shared_from_this的一个方法,允许继承类获取一个只想自身的shared_ptr智能指针,这个智能指针与已有的shared_ptr共享所有权。具体的使用方法如下#include<memory>#include<iostream>class A : public std::enable_shared_from_this<A>{ public: A(){ std::cou

JS中的块级作用域_js申明的函数有块级作用域吗_yihuoZhou的博客-程序员宅基地

JS中是没有块级作用域作用域这个概念,为实现块级作用域可通过闭包的形式实现,下面通过一个例子来说一下JS中的块级作用域。function outputName(count){ for (var i = 0; i <count; i++) { console.log(i); } } cons

实现Java Web程序的自动登录_Sodaslay的博客-程序员宅基地

有很多Web程序中第一次登录后,在一定时间内(如2个小时)再次访问同一个Web程序时就无需再次登录,而是直接进入程序的主界面(仅限于本机)。实现这个功能关键就是服务端要识别客户的身份。而用Cookie是最简单的身从验证。如果用户第一次登录,可以将用户名作为Cookie写到本地,代码如下:Cookie cookie = new Cookie("user", user);coo

随便推点

关于在ibatis中使用数据库中没有的字段,进行查找数据_实体类中有数据库没有的字段怎么查出来_Alasdair_lu的博客-程序员宅基地

首先在这里我很庆幸,终于又解决一个bug,真是bug缠身啊。希望大家相互讨论————菜菜的程序员第一点:先从实体类开始吧,今天要做一个项目,因为查询需要很多字段,但是数据库中没有,这些字段。所以想法有点,扩展原来的实体类。roomQueryVopackage com.hotelsystem.pojo.vo;import com.hotelsystem.pojo.Room;//包装类:...

关于iOS学习进阶的必读一些博客总结_weixin_30318645的博客-程序员宅基地

iOS 开发 进阶 博客http://www.jianshu.com/p/c47c24ab1e76转载于:https://www.cnblogs.com/Ghosgt/p/7650544.html

gulp 压缩css gulp-clean-css_github_39051926的博客-程序员宅基地

1.安装插件gulp-clean-cssnpm install gulp-clean-css --save-dev2.配置gulpfile.jsvar gulp = require(&quot;gulp&quot;);var cssmin = require('gulp-clean-css');//压缩cssgulp.task('testCssmin', function () {    gulp.src('Weba...

【XCTF 攻防世界】杂项 misc 高手进阶区 hit-the-core_攻防世界 hit-the-core_Kal1的博客-程序员宅基地

知识补充:Core文件作用、设置及用法浅析Linux下core文件我们可以使用strings命令查看字符串内容strings命令打印文件中可打印的字符每隔四个小写字母就可以看到一个大写字母,刚好是ALEXCTF 照着这个规律找下去,得到flag :ALEXCTF{K33P_7H3_g00D_w0rk_up}str='cvqAeqacLtqazEigwiXobxrCrtuiTzahfFreqc{bnjrKwgk83kgd43j85ePgb_e_rwqr7fvbmHjklo3tews_hmko

[Android]Toolbar_Hdnw的博客-程序员宅基地

Toolbar是由AndroidX库提供的,它的强大之处在于,它不仅继承了ActionBar的所有功能,并且灵活度很高,可以配合其他控件完成一些Material Design的效果。Theme.MaterialComponents.DayNight.NoActionBar:表示浅色主题,它会将界面的主题颜色设成浅色,陪衬颜色设为深色。Theme.MaterialComponents.NoActionBar:表示深色主题,它会将界面的主题颜色设成深色,陪衬颜色设为浅色。在themes的两个xml文件中,