首页 > 其他 > 详细

10. 门面模式与装饰器模式

时间:2021-03-30 16:11:11      阅读:15      评论:0      收藏:0      [点我收藏+]

一、门面模式

1、门面模式(Facade Pattern)又叫外观模式,提供了一个统一的接口,用来访问一群子系统中的接口。

2、特征,定义了一个高层接口,让子系统更容易使用

3、属于《结构性模式》

使用场景

1、子系统越来越复杂,增加门面模式提供简单接口。

2、构建多层系统结构,利用门面对象作为每层的入口,简化层间调用。

1. 代码示例

// 外观角色 Facade
public class Facade {
    private SubSystemA a = new SubSystemA();
    private SubSystemB b = new SubSystemB();
    private SubSystemC c = new SubSystemC();
    // 对外接口
    public void doA() {
        this.a.doA();
    }
    // 对外接口
    public void doB() {
        this.b.doB();
    }
    // 对外接口
    public void doC() {
        this.c.doC();
    }
}
// 子系统
public class SubSystemA {
    public void doA() {
        System.out.println("doing A stuff");
    }
}
// 子系统
public class SubSystemB {
    public void doB() {
        System.out.println("doing B stuff");
    }
}
// 子系统
public class SubSystemC {
    public void doC() {
        System.out.println("doing C stuff");
    }
}
// 客户
public static void main(String[] args) {
    Facade facade = new Facade();
    facade.doA();
    facade.doB();
    facade.doC();
}

技术分享图片

2. 业务模拟

商城积分兑换商品

//支付服务
public class PaymentService {
    public boolean pay(GiftInfo giftInfo){
        System.out.println("扣减" + giftInfo.getName() + " 积分成功");
        return true;
    }
}
//校验服务
public class QualifyService {
    public boolean isAvailable(GiftInfo giftInfo){
        System.out.println("校验" +giftInfo.getName() + "积分通过,库存通过。");
        return true;
    }
}
//物流服务
public class ShippingService {
    public String delivery(GiftInfo giftInfo){
        System.out.println(giftInfo.getName() + "进入物流系统");
        String shippingNo = "666";
        return shippingNo;
    }
}
//商品
public class GiftInfo {
    private String name;
    public GiftInfo(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
//测试
public static void main(String[] args) {
    QualifyService qualifyService = new QualifyService();
    PaymentService paymentService = new PaymentService();
    ShippingService shippingService = new ShippingService();
    GiftInfo giftInfo = new GiftInfo("《Spring 5核心原理》");
    if(qualifyService.isAvailable(giftInfo)){
        if(paymentService.pay(giftInfo)){
            String shippingNo = shippingService.delivery(giftInfo);
            System.out.println("物流系统下单成功,物流单号是:" + shippingNo);
        }
    }
}

门面模式改进

//门面服务(调用支付,校验,物流等多个服务)
public class FacadeService {
    private QualifyService qualifyService = new QualifyService();
    private PaymentService paymentService = new PaymentService();
    private ShippingService shippingService = new ShippingService();
    public void exchange(GiftInfo giftInfo){
        if(qualifyService.isAvailable(giftInfo)){
            if(paymentService.pay(giftInfo)){
                String shippingNo = shippingService.delivery(giftInfo);
                System.out.println("物流系统下单成功,物流单号是:" + shippingNo);
            }
        }
    }
}
//再次测试
public static void main(String[] args) {
    FacadeService facadeService = new FacadeService();
    GiftInfo giftInfo = new GiftInfo("《Spring 5核心原理》");
    facadeService.exchange(giftInfo);
}

技术分享图片

1、实际上,工作中一直都在用门面模式,例如常用的 Controller,逻辑代码 [ DistributedService ] 等....

2、各种 Utils 工具包 都是门面模式。

3. 源码举例

1、Spring JDBC 模块下的 JdbcUtils 类,封装了 JDBC 的相关操作。

2、Mybatis 中 Configuration 类中有很多 new 开头的方法

3、在 Tomcat 中也有体现,例如 RequestFacade 类

4. 模式对比

1)门面模式与代理模式

1、门面模式就是一种代理模式,只不过它是特殊的静态代理模式

2、门面模式 重点在于封装

3、静态代理 重点在于增强

4、不做增强的静态代理就是门面模式

2)门面模式与委派模式

1、委派模式也是一种静态代理模式

2、门面模式与代理模式都属于《结构型模式》

3、委派模式属于《行为型模式》,并且不属于《 GOF 23 》

3)门面模式与单例模式

1、门面模式一般都做成单例,例如各种 Utils 工具包

2、门面模式也是一种组合模式

5. 优缺点

1)优点

1、简单调用过程,无需深入了解子系统,以防给子系统带来风险

2、减少系统依赖,松散耦合

3、更好的划分访问层次,提高了安全性

4、遵循迪米特法则,即最少知道原则

2)缺点

1、当增加子系统和扩展子系统行为时,可能容易带来未知风险

2、不符合开闭原则

3、某些情况下可能违背单一职责原则 [ 整合的内容过多 ]

二、装饰器模式

1、装饰器模式(Decorator Pattern)也叫包装模式(Wrapper Pattern),是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能)

2、属于《结构型模式》

使用场景

1、用于扩展一个类的功能或给一个类添加附加职责

2、动态的给一个对象添加功能,这些功能可以再动态的撤销

1. 代码示例

//抽象功能
public abstract class Component {
    public abstract void operation();  
}
//标配
public class ConcreteComponent extends Component {
    public void operation() {  
        System.out.println("处理业务逻辑");
    }
}
//装饰器扩展入口
public abstract class Decorator extends Component {
    // 持有组件对象   
    protected Component component;  
    /** 
     * 构造方法,传入组件对象 
     * @param component 组件对象 
     */  
    public Decorator(Component component) {  
        this.component = component;  
    }  
    public void operation() {  
        //转发请求给组件对象,可以在转发前后执行一些附加动作  
        component.operation();  
    }  
} 
//扩展A
public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {  
        super(component);  
    }  
    private void operationFirst(){ } //在调用父类的operation方法之前需要执行的操作  
    private void operationLast(){ } //在调用父类的operation方法之后需要执行的操作  
    public void operation() {  
        //调用父类的方法,可以在调用前后执行一些附加动作  
        operationFirst(); //添加的功能  
        super.operation();  //这里可以选择性的调用父类的方法,如果不调用则相当于完全改写了方法,实现了新的功能  
        operationLast(); //添加的功能  
   }  
} 
//扩展B
public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);  
    }  
    private void operationFirst(){ } //在调用父类的operation方法之前需要执行的操作  
    private void operationLast(){ } //在调用父类的operation方法之后需要执行的操作  
    public void operation() {  
        //调用父类的方法,可以在调用前后执行一些附加动作  
        operationFirst(); //添加的功能  
        super.operation();  //这里可以选择性的调用父类的方法,如果不调用则相当于完全改写了方法,实现了新的功能  
        operationLast(); //添加的功能  
    }  
}  
//测试
public static void main(String[] args){
	Component c1 = new ConcreteComponent (); //首先创建需要被装饰的原始对象(即要被装饰的对象)
	Decorator decoratorA = new ConcreteDecoratorA(c1); //给对象透明的增加功能A并调用
	decoratorA .operation();
	Decorator decoratorB = new ConcreteDecoratorB(c1); //给对象透明的增加功能B并调用
	decoratorB .operation();
    Decorator decoratorBandA = new ConcreteDecoratorB(decoratorA);//装饰器也可以装饰具体的装饰对象,此时相当于给对象在增加A的功能基础上在添加功能B
    decoratorBandA.operation();
}

技术分享图片

2. 业务代码

摊煎饼,加鸡蛋?加肠?各加多少个?

//煎饼
public class Battercake {
    protected String getMsg(){ return "煎饼";}
    public int getPrice(){ return 5;}
}
//加鸡蛋
public class BattercakeWithEgg extends Battercake {
    protected String getMsg(){ return super.getMsg() + "+1个鸡蛋";}
    public int getPrice(){ return super.getPrice() + 1;}
}
//加鸡蛋加香肠
public class BattercakeWithEggAndSauage extends BattercakeWithEgg {
    protected String getMsg(){ return super.getMsg() + "+1根香肠";}
    public int getPrice(){ return super.getPrice() + 2;}
}
//....加俩鸡蛋或加俩香肠,继承无法有效的实现每种情况
//测试
public static void main(String[] args) {
    Battercake battercake = new Battercake();
    System.out.println(battercake.getMsg() + ",总价:" + battercake.getPrice());

    BattercakeWithEgg battercakeWithEgg = new BattercakeWithEgg();
    System.out.println(battercakeWithEgg.getMsg() + ",总价:" + battercakeWithEgg.getPrice());

    BattercakeWithEggAndSauage battercakeWithEggAndSauage = new BattercakeWithEggAndSauage();
    System.out.println(battercakeWithEggAndSauage.getMsg() + ",总价:" + battercakeWithEggAndSauage.getPrice());
}

装饰器改进方案

//煎饼抽象功能
public abstract class Battercake {
    protected abstract String getMsg();
    protected abstract int getPrice();
}
//标配,什么都不加
public class BaseBattercake extends Battercake{
    protected String getMsg(){ return "煎饼";}
    public int getPrice(){ return 5;}
}
//装饰器功能入口
public class BattercakeDecorator extends Battercake{
    private Battercake battercake;
    public BattercakeDecorator(Battercake battercake) {
        this.battercake = battercake;
    }
    protected String getMsg(){ return this.battercake.getMsg();}
    public int getPrice(){ return this.battercake.getPrice();}
}
//扩展功能,加1个鸡蛋
public class EggDecorator extends BattercakeDecorator{
    public EggDecorator(Battercake battercake) {
        super(battercake);
    }
    protected String getMsg(){ return super.getMsg() + "1个鸡蛋";}
    public int getPrice(){ return super.getPrice() + 1;}
}
//扩展功能,加一根香肠
public class SauageDecorator extends BattercakeDecorator{
    public SauageDecorator(Battercake battercake) {
        super(battercake);
    }
    protected String getMsg(){ return super.getMsg() + "1根香肠";}
    public int getPrice(){ return super.getPrice() + 2;}
}
//调用测试
public static void main(String[] args) {
    Battercake battercake;
    battercake = new BaseBattercake();
    battercake = new EggDecorator(battercake);
    battercake = new SauageDecorator(battercake);
    battercake = new EggDecorator(battercake);
    //加了两个鸡蛋一根香肠
    System.out.println(battercake.getMsg() + ",总价" + battercake.getPrice());
}

技术分享图片

3. 源码举例

1、在 JDK 中体现最明显的类就是 IO 相关的类

2、在 Spring 中的 TransactionAwareCacheDecorator 类,这个类主要处理缓存

3、Mybatis 中的一段处理缓存的设计 org.apache.ibatis.cache.Cache.decorators 包下的类

4. 模式对比

1)装饰器模式与代理模式

1、装饰器模式就是一种特殊的代理模式

2、装饰器模式强调自身的功能扩展,透明的扩展 [用户自己说了算],可动态定制的扩展

3、代理模式强调代理过程的控制

5. 优缺点

1)优点

1、装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态的给一个对象扩展功能,即插即用

2、通过使用不同装饰类以及这些装饰类的排列组合,可实现不同效果

3、装饰器完全遵守开闭原则

2)缺点

1、会出现更多的代码,更多的类,增加程序复杂性

2、动态装饰时,多层装饰时会更复杂

10. 门面模式与装饰器模式

原文:https://www.cnblogs.com/JustDoIt-1221/p/14596236.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!