设计模式心得:金蝶EAS与Facade门面模式

吐槽一下Facade

Facade这是一个很摸不着头脑的词,翻译是门面模式,简直就是一脸懵逼。理解为店铺模式,估计更好。

什么是Facade

曾看到过一个更有好玩的形象例子:

  我有一个专业的Nikon相机,我就喜欢自己手动调光圈、快门,这样照出来的照片才专业,但MM可不懂这些,教了半天也不会。幸好相机有Facade设计模式,把相机调整到自动档,只要对准目标按快门就行了,一切由相机自动调整, 这样MM也可以用这个相机给我拍张照片了。

门面模式

  外部与一个子系统的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。每一个子系统只有一个门面类,而且此门面类只有一个实例,也就是说它是一个单例模式。但整个系统可以有多个门面类。
设计模式心得:金蝶EAS与Facade门面模式_第1张图片
Facade模式正是这样一个”门面”:我们本来需要与后台的多个类或者接口打交道,而Facade模式是客户端和后台之间插入一个中间层——门面,这个门面跟后台的多个类或接口打交道,而客户端只需要跟门面打交道即可。

Facade模式是client与server交互过程的一个优化,是简化”客户”与”服务”交互的一种手段,注意这是一个交互优化。

使用Facade模式可以说是后台设计和编码人员的一个必备素质。我不止碰到过一个这样的后台开发人员,他们认为只要把后台功能完成了就万事大吉,而没有站在后台使用者的角度来看一看自己写出来的代码。其实,我们写出来的后台代码是要给别人使用的,所以我们提供给使用者的接口要越简单越好,这不单是对使用者好,同时对开发者也是好处多多的,至少你的接口简单了,你和使用者的交流就容易了。

而Facade模式中的Facade类正是这样一个用户接口,它和后台中的多个类产生依赖关系,而后台的客户类则只跟Facade类产生依赖关系。为什么要这么做?其中的原因十分简单:后台的开发者熟悉他自己开发的各个类,也就容易解决和多个类的依赖关系,而后台的使用者则不太熟悉后台的各个类,不容易处理和它们之间的依赖;因此,后台的开发者自己在Facade类中解决了与后台多个类之间的依赖,后台的使用者只需要处理和Facade类的依赖即可。

使用Facade模式更多的是为了第三方调用起来简单快速,把复杂的事务逻辑封装起来。

好了,闲话少说。我们下面就以几个具体的例子来看一看Facade模式是怎么使用的。实际编程中,能使用到Facade模式的情况有很多,以下就分两种情况来具体说一说Facade模式的使用。可能还会有其他的情况,大家在实践中也可以加以补充。
第一种情况,客户类要使用的功能分布在多个类中,这些类可能相互之间没有什么关系;客户在使用后台的时候,必须先初始化要使用到的功能所在的类,然后才能使用。这时候,适合将这些功能集中在一个Facade类里,还可以替用户做一些初始化的工作,以减轻用户的负担。
例如,以商店为例。假如商店里出售三种商品:衣服、电脑和手机。这三种商品都是由各自的生产厂商卖出的,如下:

public class CoatFactory
{
    public Coat saleCoat()
    {
    ……
    return coat;
    }
    ……
}

然后是电脑的厂家类:

public class ComputerFactory
{
    public Computer saleComputer()
    {
    ……
    return computer;
    }
    ……
}

最后是手机商类:

public class MobileFactory
{
    public Mobile saleMobile()
    {
    ……
    return mobile;
    }
    ……
}

如果没有商店,我们就不得不分别跟各自的生产商打交道,如下:

//买衣服
CoatFactory coatFactory = new CoatFactory();
coatFactory.saleCoat();
//买电脑
ComputerFactory computerFactory = new ComputerFactory();
computerFactory.saleComputer ();
//买手机
MobileFactory mobileFactory = new MobileFactory();
mobileFactory.saleMobile();

对我们顾客来说,和这么多的厂家类打交道,这显然是够麻烦的。

这样,我们就需要创建一个商店类了,让商店类和这些厂家打交道,我们只和商店类打交道即可,如下:

public class StoreFacade
{
    CoatFactory coatFactory = new CoatFactory();
    ComputerFactory computerFactory = new ComputerFactory();
    MobileFactory mobileFactory = new MobileFactory();

    public Coat saleCoat()
    {
        return coatFactory.saleCoat();
    }
    public Computer saleComputer() 
    {
        return computerFactory.saleComputer();
    }
    public Mobile saleMobile()
    {
        return mobileFactory.saleMobile ();
    }
}

好了,现在我们要买东西,不用去跟那么多的厂家类打交道了。

StoreFacade store =new StoreFacade();
//买衣服
store.saleCoat();
//买电脑
store.saleComputer();
//买手机
store.saleMobile();

EAS与Facade模式

设计模式心得:金蝶EAS与Facade门面模式_第2张图片

EAS的前端EditUIPIEx

这里一般会调用到后台一些业务,因为毕竟展现给用户看到是前端,然后请求后台的数据。

public class SaleOrderEditUIPIEx extends SaleOrderEditUI
{

    public boolean beforeAction(BatchActionEnum bizAction, BatchSelectionEntries selectionEntries, ActionEvent event)
    {
        SaleOrgUnitInfo saleOrgInfo = (SaleOrgUnitInfo) prmtSaleOrgUnit.getData();
        if (BatchActionEnum.SUBMIT.equals(bizAction)){
            //逻辑1:根据物理id获取详细物料(eas内部方法)
            MaterialInfo material=entryInfo.getMaterial();
            try {
                material = MaterialFactory.getRemoteInstance().getMaterialInfo(new ObjectUuidPK(material.getId()));
            } catch (EASBizException e1) {
                e1.printStackTrace();
            } catch (BOSException e1) {
                e1.printStackTrace();
            }
            //根据物理处理其他操作,省略

            //逻辑2:获取政策价格(自己写的后台逻辑,在SaleOrderPolicyPriceSyncFacadeBean)
            BigDecimal policyPrice=BigDecimal.ZERO;
            try {
                policyPrice = SaleOrderPolicyPriceSyncFacadeFactory.getRemoteInstance().getPolicyPriceNew(cuId, material.getId()+"", customer.getId()+"");
            } catch (EASBizException e) {
                e.printStackTrace();
            } catch (BOSException e) {
                e.printStackTrace();
            }
        }       
        return super.beforeAction(bizAction, selectionEntries, event);
    }
}

后台Facade

相当于可以看到这个Facade可以做什么(类似门店简介,看到这家店卖什么东东)
设计模式心得:金蝶EAS与Facade门面模式_第3张图片

Facade的实现ControllerBean

业务逻辑都在这里实现即可。

   /** 
     * 政策价格3.0(2018版)
     * @author zhengkai
     */
    @Override
    public BigDecimal getPolicyPriceNew(Context ctx, String orgunitid,
            String materialid, String customerid) throws BOSException,
            EASBizException {
        StringBuffer sqlString = new StringBuffer( " /*dialect*/ select ppe.fprice ");
        sqlString.append(" from t_scm_pricepolicyentry  ppe ");
        sqlString.append(" left join t_scm_pricepolicy pp ");
        sqlString.append(" on pp.fid = ppe.fparentid ");
        sqlString.append(" left join t_bd_material m  ");
        sqlString.append(" on ppe.fmaterialid=m.fid ");
        sqlString.append(" left join t_bd_customer c ");
        sqlString.append(" on ppe.fcustomerid=c.fid ");
        sqlString.append(" left join t_org_company comp ");
        sqlString.append(" on comp.fid=pp.fcontrolunitid ");
        sqlString.append(" where pp.FBLOCKEDSTATUS=1 and pp.FCHECKEDSTATUS=2 ");
        sqlString.append(" and pp.fsaleorgunitid=?  ");
        sqlString.append(" and m.fid=? ");
        sqlString.append(" and c.fid=? ");
        sqlString.append(" and sysdate between ppe.feffectivedate and ppe.fexpiredate ");
        sqlString.append(" order by pp.FPriceCompositionPriority ");
        Connection paramConn = null;
        RowSet rs = null;
        try {
            rs=DbUtil.executeQuery(ctx, sqlString.toString(), new Object[] { orgunitid,materialid,customerid });
            if(rs.next()){
                return rs.getBigDecimal(1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally{
            SQLUtils.cleanup(paramConn);
            SQLUtils.cleanup(rs);
        }
        return BigDecimal.ZERO;
    }

你可能感兴趣的:(杂谈)