设计模式——外观模式

前言

外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。

 一个复杂的过程需要高级的接口以及具体实现的实现类,对于调用者来说并不关心实现的细节,只关心结果调用和结果输出。可以拆分子系统,或则单独的类进行构造门面模式。

  • 访问一系列复杂的子系统提供一个简单的入口
  • 客户端程序与多个子系统存在很大的依赖性
  • 在层次化系统中,可以使用外观模式定义系统中每一层的入口,层与层之间不产生直接关系,而是通过外观类建立联系,降低层之间的耦合度。

1.定义一个购物过程的接口

/**
 * 定义一个购物处理过程
 */
public interface PurchurseProcess {

    //挑选商品
    void pickGoods(String goodName);

    //添加购物车
    void addCart(String goodName);

    //选择快递方式
    void chooseDelivMode(String delivName);

    //支付
    void pay();

}

接口实现类:

/**
 * 购物过程的实现类
 */
public class PurchurseProcessImpl implements PurchurseProcess{
    @Override
    public void pickGoods(String goodName) {
        System.out.println("挑选商品:"+goodName);
    }

    @Override
    public void addCart(String goodName) {
        System.out.println("将商品"+goodName+"添加购物车!");
    }

    @Override
    public void chooseDelivMode(String delivName) {
        System.out.println("选择快递方式"+delivName);
    }

    @Override
    public void pay() {
        System.out.println("进行支付....");
    }
}

简单的过程,使用外观模式前,我们需要每个步骤都得调用一次。

/**
 * 模拟一个购物下单的过程
 */
public class FacadeDemo {
    public static void main(String[] args) {
        PurchurseProcessImpl process = new PurchurseProcessImpl();
        //1.挑选物品
        process.pickGoods("联想电脑");
        //2.添加购物车
        process.addCart("联想电脑");
        //3.选择快递方式
        process.chooseDelivMode("京东快递");
        //4.支付完成
        process.pay();
    }
}

如果每个步骤都这样,步骤比较繁琐。外观模式可以帮助解决这个问题。

2.外观模式进行改造

代码如下
门面类中进行引入购买的接口类,提供一个统一接口进行购物。

/**
 * 定义门面
 */
public class PurchurseFacade {

    private PurchurseProcess purchurseProcess = new PurchurseProcessImpl();

    /**
     * 一个方法实现四个步骤
     * @param goodName 商品名字
     * @param deliveryMode 快递方式
     */
   public void purchurseGoods(String goodName,String deliveryMode) {
       //1.挑选物品
       purchurseProcess.pickGoods(goodName);
       //2.添加购物车
       purchurseProcess.addCart(goodName);

       //3.选择快递方式
       purchurseProcess.chooseDelivMode(deliveryMode);

       //4.支付完成
       purchurseProcess.pay();
   }
}

这样我们调用就简单多了,调用代码如下:


public class Client {
    public static void main(String[] args) {
        PurchurseFacade purchurseFacade = new PurchurseFacade();
        //购买过程
        purchurseFacade.purchurseGoods("华为mate30","圆通快递");
    }
}

3. 思考

如果添加步骤呢,选择支付方式,选择快递地址呢,我们还需要进行步骤拆分,但是对于调用者来说并不关心步骤,只关心结果。
支付方式:

/**
 * 选择支付方式
 */
public class PayModeFacde {
    /**
     * 选择支付方式
     * @param payMode
     */
    public void selectPayMode(String payMode){
        System.out.println("选择支付方式:"+payMode);
    }
}

快递地址:

/**
 * 增加选择邮件地址
 */
public class DeliveryAddress {
    /**
     * 选择邮寄地址
     * @param address
     */
    public void addAddress(String address){
        System.out.println("选择邮寄地址:"+address);
    }

}

原来的类进行改造,添加额外增加的功能步骤:
//增加选择地址 private DeliveryAddress deliveryAddress = new DeliveryAddress(); //选择支付方式 private PayModeFacde payModeFacde = new PayModeFacde();

/**
 * 定义门面
 */
public class PurchurseFacade {

    private PurchurseProcess purchurseProcess = new PurchurseProcessImpl();

    //增加选择地址
    private  DeliveryAddress deliveryAddress = new DeliveryAddress();
    //选择支付方式
    private PayModeFacde payModeFacde = new PayModeFacde();

    /**
     * 一个方法实现四个步骤
     * @param goodName 商品名字
     * @param deliveryMode 快递方式
     */
   public void purchurseGoods(String goodName,String deliveryMode) {
       //1.挑选物品
       purchurseProcess.pickGoods(goodName);
       //2.添加购物车
       purchurseProcess.addCart(goodName);
       //添加快递地址
       deliveryAddress.addAddress("xx省");
       //3.选择快递方式
       purchurseProcess.chooseDelivMode(deliveryMode);
       //增加
       payModeFacde.selectPayMode("支付宝");
       //4.支付完成
       purchurseProcess.pay();
   }
}

输出结果:

挑选商品:华为mate30
将商品华为mate30添加购物车!
选择邮寄地址:xx省
选择快递方式圆通快递
选择支付方式:支付宝
进行支付....

Mybatis源码 Configuration结构分析

在这里插入图片描述

 由上面的类图可以看出,client只需要调用Configuration的newMetaObject(Object object)方法就可以得到一个MetaObject对象,而具体的对象是怎么生成与client无关,下面我们可以看一下Configuration的部分源码分析。 

//Configuration 类:
public class Configuration {
	protected ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
	protected ObjectFactory objectFactory = new DefaultObjectFactory();
  	protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();

	 public MetaObject newMetaObject(Object object) {
    	return MetaObject.forObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    }
}

//MetaObject类
public class MetaObject {
	private Object originalObject;
	private ObjectWrapper objectWrapper;
	private ObjectFactory objectFactory;
	private ObjectWrapperFactory objectWrapperFactory;
	private ReflectorFactory reflectorFactory;

	public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    	if (object == null) {
    		return SystemMetaObject.NULL_META_OBJECT;
    	} else {
      		return new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
    	}
 	}

	private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
    	this.originalObject = object;
    	this.objectFactory = objectFactory;
    	this.objectWrapperFactory = objectWrapperFactory;
   		this.reflectorFactory = reflectorFactory;

    	if (object instanceof ObjectWrapper) {
      		this.objectWrapper = (ObjectWrapper) object;
    	} else if (objectWrapperFactory.hasWrapperFor(object)) {
      		this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    	} else if (object instanceof Map) {
      		this.objectWrapper = new MapWrapper(this, (Map) object);
    	} else if (object instanceof Collection) {
     		this.objectWrapper = new CollectionWrapper(this, (Collection) object);
    	} else {
      		this.objectWrapper = new BeanWrapper(this, object);
  		}
	}
}

由上面的部分源码可以看出,客户端只需要调用ConfigurationnewMetaObject(Object object)方法,并传递一个Object参数,就可以获取对应的MetaObject,至于具体的产生什么样的MetaObject,则有MetaObject的类的forObject(object, objectFactory, objectWrapperFactory, reflectorFactory)方法实现。

源码解析(Tomcat ServletRequest)

使用tomcat作为web容器时,接收浏览器发送过来的请求,tomcat会将请求信息封装成ServletRequest对象,如下图①处对象。但是大家想想ServletRequest是一个接口,它还有一个子接口HttpServletRequest,而我们知道该request对象肯定是一个HttpServletRequest对象的子实现类对象,到底是哪个类的对象呢?可以通过输出request对象,我们就会发现是一个名为RequestFacade的类的对象。
在这里插入图片描述

 RequestFacade类就使用了外观模式。先看结构图:

在这里插入图片描述

为什么在此处使用外观模式呢?

 定义RequestFacade类,分别实现 ServletRequest ,同时定义私有成员变量 Request ,并且方法的实现调用 Request的实现。然后,将 RequestFacade上转为 ServletRequest 传给servlet service方法,这样即使在 servlet 中被下转为RequestFacade ,也不能访问私有成员变量对象中的方法。既用了 Request ,又能防止其中方法被不合理的访问。
 

总结

可以看出外观模式并不符合开闭原则,需要修改原来的接口代码进行改造,比如日志输出 ,我们并不关心日志如何实现的,只需要引入日志相关的类。


————————————————
版权声明:本文为CSDN博主「小刘同学要加油呀」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_37400096/article/details/126979857

相关文章:

Java 设计模式 – 外观模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值