重学设计模式(三设计模式-外观模式)

Posted 穆瑾轩

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重学设计模式(三设计模式-外观模式)相关的知识,希望对你有一定的参考价值。

1、外观模式

    面向对象编程的最大优势,在于它能够防止应用程序成为混乱的小块程序。当我们的应用程序和复杂库或框架的大量对象一起工作,通常需要初始化这些对象,并引入相应的依赖关系,以正确的执行方法。这样你的类的业务将与第三方库或框架的实现细节紧密的耦合,使其难以理解和维护。外观模式就是用来解决这个问题的。

1.1、什么是外观模式

  • 定义

    外观(Facade)模式又叫作门面模式,是一种通过为多个复杂的子系统提供统一的入口,封装子系统的复杂性,便于客户端调用。

    外观(Facade)模式是“迪米特法则”的典型应用,在日常编码工作中,我们都在有意无意的大量使用外观模式。

    只要是高层模块需要调度多个子系统(这里的子系统可以是一个完整的系统,也可以是模块或者更细粒度的类的对象),我们都会自觉地创建一个新的类封装这些子系统,提供精简的接口(只暴露有限的必要接口),让高层模块可以更加容易地间接调用这些子系统的功能,说白了就是封装系统的底层实现,隐藏系统的复杂性,提供一组更加简单易用、更高层的接口。比如:我们平时写的一些Utils类(DButils)可以理解为Facade;Linux 系统调用函数,它封装了底层更基础的 Linux 内核调用。

    外观模式的意图在于:为多个复杂的子系统提供统一的入口,来简化客户端的调用。

外观模式的结构:

    1)外观(Facade)角色:为多个子系统对外提供一个共同的接口;

    2)子系统(Sub System)角色:实现系统的部分功能,客户可以通过外观角色访问它。

    3)客户(Client)角色:通过一个外观角色访问各个子系统的功能,而不是直接调用子系统。

1.2、外观模式的优缺点

  • 优点

1)可以将代码与子系统的复杂性隔离开来,降低了子系统与客户端之间的耦合度;

2)屏蔽了子系统组件,减少了客户处理的对象数目,并使得子系统使用起来更加容易。

  • 缺点

违背了“开闭原则”,增加新的子系统可能需要修改外观类或客户端的代码。

1.3、创建方式

    我们可能经常会使用积分兑换一些物品,这里我们就以信用卡积分兑换为例。客户可能会选择兑换的礼品,我们首先会校验是否能兑换,然后扣除积分兑换成功,最后进入物流系统等待收货。

1)先声明礼品信息Gift

//礼品信息
public class Gift 

	private String name; //礼品名称
	
	private Integer score; //积分
	
	public Gift(String name,Integer score)
		this.name = name;
		this.score = score;
	

	public String getName() 
		return name;
	

	public Integer getScore() 
		return score;
	

2)积分验证子系统

//积分验证子系统,为了简便子系统一般实现接口
public class Verification 

	public boolean isAvailable(String custid,Gift gift)
		//查询custid客户积分custScore
		Integer custScore = 9999999;
		if(custScore <gift.getScore())
			System.out.println("您的积分不足,无法兑换");
			return false;
		
		System.out.println("积分校验成功,积分可以兑换");
		return true;
	

3)积分支付子系统

//积分支付子系统,为了简便子系统一般实现接口
public class PayScore 

	public boolean pay(String custId,Gift gift)
		//custId获取客户信息,积分totalScore
		//扣除客户积分:totalScore - gift.getScore();
		System.out.println("积分扣减成功");
		return true;
	

4)物流子系统

//物流子系统,为了简便子系统一般实现接口
public class Logistics 

	public boolean SendLogistics(String custid,Gift gift)
		System.out.println(custid+"的礼品:"+gift.getName()+"-物流发送成功");
		return true;
	

5)当没有使用外观规模,客户端的调用过程,比较复杂

//没有使用外观模式的客户端
public class Client 

	public static void main(String[] args) 
		String custid = "1号客户";
		Gift gift = new Gift("微波炉",999);
		//积分校验
		Verification vf = new Verification();
		if(!vf.isAvailable(custid,gift))
            return;
        
		//支付积分
		PayScore ps = new PayScore();
		ps.pay(custid, gift);
		//物流发送
		Logistics ls = new Logistics();
		ls.SendLogistics(custid, gift);
	

6)使用外观模式(门面模式)

public class jfSystemFacade 
	//复习下,聚合是has-a关系,整体与部分关系弱,组合是contains-a关系,整体与部分关系强
	private Verification vf;
	private PayScore ps;
	private Logistics ls;
	
	public jfSystemFacade()
		vf = new Verification();
		ps = new PayScore();
		ls = new Logistics();
	

	public boolean ScoreExchange(String custid,Gift gift)
		//积分校验
		if(!vf.isAvailable(custid,gift))
			return false;
		
		//支付积分
		ps.pay(custid, gift);
		//物流发送
		ls.SendLogistics(custid, gift);
		return true;
	

7)此时的客户端

//使用外观模式的客户端,客户端的调用精简了很多
public class Client 

	public static void main(String[] args) 
		String custid = "1号客户";
		Gift gift = new Gift("微波炉",999);
		jfSystemFacade fd = new jfSystemFacade();
		fd.ScoreExchange(custid, gift);
	

此时的UML关系图:

1.4、总结及建议

    外观模式更像是客户端应用程序的助手,其本质就是整合接口,封装低层实现细节,为客户端提供一个更简洁的接口,实现了子系统与客户端间的松耦合关系。

应用场景:

    1)当您需要一个有限但直接的接口来连接复杂的子系统时,可以使用外观模式;

    2)当客户端与多个子系统之间存在很大的联系时,引入外观模式可将它们分离,从而提高子系统的独立性和可移植性。

    3)防止客户端将对象转换为更底层的真实对象,隐藏底层不必要暴露给客户端的一些方法或属性。

JDK中外观模式的应用:

    在java类库中直接使用门面模式的并不多,作为java开发者,通常需要对类库中的工具做整体的了解,外观模式可能会使得类库变得复杂,让人使用者产生误解。

    不过在Tomcat中就有大量的外观模式的应用。因为Tomcat中有很多不同组件,每个组件要相互通信,但是又不能将自己内部数据过多的暴露给其他组件。

org.apache.catalina.connector.HttpRequestFacade

org.apache.catalina.connector.HttpResponseFacade

以上是关于重学设计模式(三设计模式-外观模式)的主要内容,如果未能解决你的问题,请参考以下文章

外观模式

重学设计模式(三设计模式-解释器模式)

重学设计模式(三设计模式-解释器模式)

重学设计模式(三设计模式-原型模式)

2 结构型模式之 - 外观模式

重学设计模式(三设计模式-桥接模式)