• 设计模式06-门面模式与装饰器模式


    1.6门面模式与装饰器模式详解

    1.6.1.门面模式详解

    时长:39min

    内容预演:

    》模式的特征和应用场景

    》装饰器模式与代理模式的区别

    》门面模式的优缺点

    》装饰器模式的优缺点

    1.6.1.1.什么是门面模式?

    定义:

      Facade Pattern,又称外观模式。提供一个统一的接口,用来访问子系统中的一群接口。

    属于结构型设计模式。

    特征:

      门面模式定义一个高层接口,让子系统更容易使用。

    1.门面模式的适用场景

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

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

    2.生活中门面模式运用

      前台接待员【前台---为公司做导向】

      包工头

    1.6.1.2.门面模式的实现

    1.通用实现

      这里以测试驱动开发【TDD】的方式进行开发。

    【1】定义测试类
    package com.wf.facade.general;
    
    /**
     * @ClassName FacadeTest
     * @Description 测试
     * @Author wf
     * @Date 2020/5/21 14:45
     * @Version 1.0
     */
    public class FacadeTest {
        public static void main(String[] args) {
            //客户端调用,门面的实例
            Facade facade = new Facade();
            facade.doWorkA();
            facade.doWorkB();
            facade.doWorkC();
        }
    }
    [2]创建门面类Facade

     根据报错,开发子系统服务。具体代码实现如下:

    package com.wf.facade.general;
    
    /**
     * @ClassName Facade
     * @Description 门面类,这里只是简单调用子系统服务
     * @Author wf
     * @Date 2020/5/21 14:46
     * @Version 1.0
     */
    public class Facade {
        private SubSystemA a = new SubSystemA();
        private SubSystemB b = new SubSystemB();
        private SubSystemC c = new SubSystemC();
    
        public void doWorkA() {
            this.a.doWorkA();
        }
    
        public void doWorkB() {
            this.b.doWorkB();
        }
    
        public void doWorkC() {
            this.c.doWorkC();
        }
    }
    [3]定义子系统服务

    A.子系统A

    package com.wf.facade.general;
    
    /**
     * @ClassName SubSystemA
     * @Description 子系统服务
     * @Author wf
     * @Date 2020/5/21 14:57
     * @Version 1.0
     */
    public class SubSystemA {
        public void doWorkA() {
            System.out.println("子系统A提供服务");
        }
    }

     2.子系统服务B

    package com.wf.facade.general;
    
    /**
     * @ClassName SubSystemB
     * @Description 子系统服务
     * @Author wf
     * @Date 2020/5/21 14:58
     * @Version 1.0
     */
    public class SubSystemB {
        public void doWorkB() {
            System.out.println("子系统B提供服务");
        }
    }

    3.子系统服务C 

    package com.wf.facade.general;
    
    /**
     * @ClassName SubSystemC
     * @Description 子系统服务
     * @Author wf
     * @Date 2020/5/21 14:58
     * @Version 1.0
     */
    public class SubSystemC {
        public void doWorkC() {
            System.out.println("子系统C提供服务");
        }
    }
     【4】.测试结果

    说明:

      门面模式,只是把所有的工作都交给门面类来统一处理,客户端只和一个人进行交接,简化客户端的使用

      我们在web开发中,Controller就是一种门面模式的应用。

     【5】系统类图分析

    2.实际场景实现

      有一个社区商城,它不是直接通过付费进行购买礼品。而是通过积分兑换,当对一个礼品有兴趣时,通常点击商品图片,

    进入商品详情页,商品下边提供立即兑换功能。当点击兑换时,弹出表单,获取用户信息【自己填写表单】,如:姓名,电话,邮箱,备注,

    然后确定兑换。会判断你的积分是否足够,如果积分足够,就发起一个支付动作,否则无法兑换。

      

      支付完成后,进入物流信息记录。发货时间,订单号。。。

      这样一个购物流程,如果全部由前端来控制,需要调用大量的接口,前端工作量会很大,调用会很复杂,那么,该怎么办呢?

    为了提升开发效率,减轻前端开发工作量,后端可以统一封装一个接口,控制整个流程。

    系统设计:

      分析业务bean【礼品GiftInfo】

      系统构成:支付系统PaymentService----》库存系统QualifyService【校验积分是否足够】-----》物流系统ShippingService

    [1]业务bean定义
    package com.wf.facade.points;
    
    /**
     * @ClassName GiftInfo
     * @Description 业务类,礼品信息
     * @Author wf
     * @Date 2020/5/21 15:26
     * @Version 1.0
     */
    public class GiftInfo {
        private String name;
    
        public GiftInfo(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    }
    【2】库存系统
    package com.wf.facade.points;
    
    /**
     * @ClassName QualifyService
     * @Description 库存系统
     * @Author wf
     * @Date 2020/5/21 15:29
     * @Version 1.0
     */
    public class QualifyService {
        public boolean isAvailable(GiftInfo giftInfo){
            System.out.println("校验 " + giftInfo.getName()+" 积分足够,库存足够,允许兑换");
            return true;
        }
    }
    【3】支付系统 
    package com.wf.facade.points;
    
    /**
     * @ClassName PaymentService
     * @Description 支付系统
     * @Author wf
     * @Date 2020/5/21 15:34
     * @Version 1.0
     */
    public class PaymentService {
        public boolean pay(GiftInfo giftInfo){
            System.out.println("扣减 "+giftInfo.getName() + " 积分成功");
            return true;
        }
    }
     【4】物流系统
    package com.wf.facade.points;
    
    /**
     * @ClassName ShippingService
     * @Description 物流系统
     * @Author wf
     * @Date 2020/5/21 15:32
     * @Version 1.0
     */
    public class ShippingService {
        public String delivery(GiftInfo giftInfo){
            System.out.println(giftInfo.getName() + " 进入物流系统");
            String shippingNO= "666";
            return shippingNO;
        }
    }
    【5】模拟客户端调用
    package com.wf.facade.points;
    
    /**
     * @ClassName Test
     * @Description 测试,模拟前端调用
     * @Author wf
     * @Date 2020/5/21 15:42
     * @Version 1.0
     */
    public class Test {
        public static void main(String[] args) {
            QualifyService qualifyService = new QualifyService();
            PaymentService paymentService = new PaymentService();
            ShippingService shippingService = new ShippingService();
    
            //判断积分是否足够
            GiftInfo giftInfo = new GiftInfo("《spring5 核心原理解析》");
            if(qualifyService.isAvailable(giftInfo)){
                if(paymentService.pay(giftInfo)){
                    String shippingNO = shippingService.delivery(giftInfo);
                    System.out.println("物流系统下单成功,物流单号是:"+shippingNO);
                }
            }
        }
    }
     测试结果如下:

    说明:

      整个系统功能开发完成,但是客户端调用复杂,为简化调用,使用门面模式,增加门面类:

    【5】增加门面类
    package com.wf.facade.points;
    
    /**
     * @ClassName FacadeService
     * @Description 门面类
     * @Author wf
     * @Date 2020/5/21 17:47
     * @Version 1.0
     */
    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);
                }
            }
        }
    }
    【6】修改测试类
     public static void main(String[] args) {
            FacadeService facadeService = new FacadeService();
            //判断积分是否足够
            GiftInfo giftInfo = new GiftInfo("《spring5 核心原理解析》");
           facadeService.exchange(giftInfo);
        }
    说明:
      运行结果一致,客户端代码调用,变得简单。
      这就是门面模式,我们的代码中基本每天都在使用它。
    【7】系统类图

    1.6.1.3.门面模式在源码中运用

    Mybatis中JdbcUtils【典型的门面模式】

    Mybatis中Configration大量使用门面模式。

    Tomcat源码中RequestFacade,ResponseFacade,StandardSessionFacade.

    1.6.1.4.门面模式的总结

    1.门面模式与代理模式的关系

      门面模式,就是一种特殊的静态代理。

      门面模式的重点,是在于封装。静态代理的重点是功能增强。不做增强的静态代理就是门面模式。

      委派模式,也是一种静态代理,代理属于结构型模式。而委派【行为型模式】,不属于GOF 23之一。

    2.门面模式与单例模式的关系

      门面类,很多时候做成单例类,如工具类。

      

    3.门面模式的优点

      》简化客户端调用,调用者无需关注子系统,以防给子系统带来风险。

      》减少系统依赖,松散耦合。

      》更好地划分访问层次,提高安全性

      》遵循迪米特法则,即最少知道原则。

      》符合组合原则

    4.门面模式的缺点

      》当增加子系统和扩展子系统行为时,可能带来未知风险。

      》不符合开闭原则

      》某些情况下可能违背单一职责原则。导致门面类职责较重。

    1.6.2.装饰器模式详解

    时长:55min

    1.6.2.1.装饰器模式的定义

    官方定义

      Decorator pattern,装饰器模式。也叫包装器模式(Wrapper Pattern),是指在不改变原有对象的基础上,将功能附加到对象上,

    提供了比继承更有弹性的替代方案(扩展原有对象的功能

      属于结构型模式。

    1.生活中的装饰器模式:

      煎饼【可以加各种辅助材料,本质不变】

      蛋糕。

    2.适用场景

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

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

    1.6.2.2.装饰器模式的代码实现

    1.通用实现

    【1】顶层功能组件

      可以定义为接口或抽象类。这里定义为抽象类。

    package com.wf.decorator.general;
    
    /**
     * @ClassName Component
     * @Description 顶层抽象功能组件
     * @Author wf
     * @Date 2020/5/21 19:12
     * @Version 1.0
     */
    public abstract class Component {
        public abstract void operation();
    }

    【2】组件的原生实现类

    package com.wf.decorator.general;
    
    /**
     * @ClassName ConcreteComponent
     * @Description 组件原生具体实现
     * @Author wf
     * @Date 2020/5/21 19:14
     * @Version 1.0
     */
    public class ConcreteComponent extends Component {
        @Override
        public void operation() {
            System.out.println("处理具体的业务逻辑");
        }
    }

    【3】装饰器抽象接口

    package com.wf.decorator.general;
    
    /**
     * @ClassName Decorator
     * @Description 装饰器抽象接口
     * @Author wf
     * @Date 2020/5/21 19:16
     * @Version 1.0
     */
    public abstract class Decorator extends Component{
        //持有组件引用
        protected  Component component;
    
        public Decorator(Component component){
            this.component = component;
        }
    
        @Override
        public void operation() {
            //转发请求给组件对象,可以在转发前后执行一些附加动作【增强组件】
            component.operation();
        }
    }

      下面可以实现不同的装饰器:

    package com.wf.decorator.general;
    
    /**
     * @ClassName ConcreteDecoratorA
     * @Description 装饰器实现子类A
     * @Author wf
     * @Date 2020/5/21 19:21
     * @Version 1.0
     */
    public class ConcreteDecoratorA extends Decorator {
        public ConcreteDecoratorA(Component component) {
            super(component);
        }
    
        @Override
        public void operation() {
            //此前添加功能
            operationFirst();
            super.operation();
            operationLast();
        }
    
        private void operationLast() {
            System.out.println("装饰器A 在调用父类方法之后执行");
        }
    
        private void operationFirst() {
            System.out.println("装饰器A 在调用父类方法之前执行");
        }
    }
    package com.wf.decorator.general;
    
    /**
     * @ClassName ConcreteDecoratorB
     * @Description 装饰器实现子类B
     * @Author wf
     * @Date 2020/5/21 19:21
     * @Version 1.0
     */
    public class ConcreteDecoratorB extends Decorator {
        public ConcreteDecoratorB(Component component) {
            super(component);
        }
    
        @Override
        public void operation() {
            //此前添加功能
            operationFirst();
            super.operation();
            operationLast();
        }
    
        private void operationLast() {
            System.out.println("装饰器B 在调用父类方法之后执行");
        }
    
        private void operationFirst() {
            System.out.println("装饰器B 在调用父类方法之前执行");
        }
    }

    【4】客户端调用

    package com.wf.decorator.general;
    
    /**
     * @ClassName Client
     * @Description 客户端调用
     * @Author wf
     * @Date 2020/5/21 19:24
     * @Version 1.0
     */
    public class Client {
        public static void main(String[] args) {
            Component component = new ConcreteComponent();
            Decorator decoratorA = new ConcreteDecoratorA(component);
            decoratorA.operation();
            System.out.println("----------------------------------");
            Decorator decoratorB = new ConcreteDecoratorB(component);
            decoratorB.operation();
            System.out.println("----------------------------------");
            Decorator decoratorBandA = new ConcreteDecoratorB(decoratorA);
            decoratorBandA.operation();
        }
    }

     执行结果如下:

     说明:

      客户端通过,构建器封装,子类调用父类的方法,进行功能增强。

    【5】系统类图

    这个示例,是装饰者模式的通用写法,因为没有针对具体需求,进行编码。所以,理解起来,还是有些抽象

    下面使用“煎饼”这个生活实例,来说明,先使用普通编码,然后再使用装饰器模式改写。对比两种实现:

    2.煎饼的普通实现
    【1】业务bean,煎饼类
    package com.wf.decorator.battercake.v1;
    
    /**
     * @ClassName Battercake
     * @Description 业务bean,煎饼类
     * @Author wf
     * @Date 2020/5/22 10:18
     * @Version 1.0
     */
    public class Battercake {
        protected String getMsg(){
            return "这是一个煎饼";
        }
    
        public int getPrice(){
            return 5;
        }
    }
    【2】编写测试类
    package com.wf.decorator.battercake.v1;
    
    /**
     * @ClassName Test
     * @Description 测试类
     * @Author wf
     * @Date 2020/5/22 10:20
     * @Version 1.0
     */
    public class Test {
        public static void main(String[] args) {
            Battercake battercake = new Battercake();
            System.out.println(battercake.getMsg()+",总价:"+battercake.getPrice()+"元钱");
        }
    }

    执行结果如下:

    说明:

      这里只是简单测试下,普通煎饼的功能。下面要对煎饼进行加料,使用继承来扩展。

    【3】加蛋煎饼
    package com.wf.decorator.battercake.v1;
    
    /**
     * @ClassName BattercakeWithEgg
     * @Description 加蛋煎饼
     * @Author wf
     * @Date 2020/5/22 10:26
     * @Version 1.0
     */
    public class BattercakeWithEgg extends Battercake {
        @Override
        protected String getMsg() {
            return super.getMsg() +",外加一个鸡蛋";
        }
    
        @Override
        public int getPrice() {
            return super.getPrice() + 1;
        }
    }
     【4】修改测试类
    package com.wf.decorator.battercake.v1;
    
    /**
     * @ClassName Test
     * @Description 测试类
     * @Author wf
     * @Date 2020/5/22 10:20
     * @Version 1.0
     */
    public class Test {
        public static void main(String[] args) {
            Battercake battercake = new Battercake();
            System.out.println(battercake.getMsg()+",总价:"+battercake.getPrice()+"元钱");
    
            Battercake battercakeWithEgg = new BattercakeWithEgg();
            System.out.println(battercakeWithEgg.getMsg()+",总价:"+battercakeWithEgg.getPrice()+"元钱");
        }
    }

    测试结果如下:

    说明:

      通过继承结构,功能得到增强。如果想再加料,加蛋基础上,再加一根香肠。又得需要深层继承。

    [5]加蛋加香肠煎饼
    package com.wf.decorator.battercake.v1;
    
    /**
     * @ClassName BattercakeWithEggAndSausage
     * @Description 加蛋加香肠煎饼
     * @Author wf
     * @Date 2020/5/22 10:33
     * @Version 1.0
     */
    public class BattercakeWithEggAndSausage extends BattercakeWithEgg {
        @Override
        protected String getMsg() {
            return super.getMsg()+",再加一根香肠";
        }
    
        @Override
        public int getPrice() {
            return super.getPrice()+2;
        }
    }
    【6】再次修改测试类
    package com.wf.decorator.battercake.v1;
    
    /**
     * @ClassName Test
     * @Description 测试类
     * @Author wf
     * @Date 2020/5/22 10:20
     * @Version 1.0
     */
    public class Test {
        public static void main(String[] args) {
            Battercake battercake = new Battercake();
            System.out.println(battercake.getMsg()+",总价:"+battercake.getPrice()+"元钱");
    
            Battercake battercakeWithEgg = new BattercakeWithEgg();
            System.out.println(battercakeWithEgg.getMsg()+",总价:"+battercakeWithEgg.getPrice()+"元钱");
    
            Battercake battercakeWithEggAndSausage = new BattercakeWithEggAndSausage();
            System.out.println(battercakeWithEggAndSausage.getMsg()+",总价:"+battercakeWithEggAndSausage.getPrice()+"元钱");
        }
    }
     运行结果如下:

     说明:  

      如果想再加料,如:加青菜,加肉,不是得再次深层继承,造成这种继承结构复杂,层次太深。

      显然,使用继承处理这种需求,是不合适的,这会造成类大量生成,顶层类一直得不到回收。

      

      前辈们,针对这种需求,总结出装饰器模式,下面使用装饰器模式改写系统。

    3.装饰器模式改写煎饼系统
    【1】抽象化顶层组件

      系统中,煎饼类,需要抽象成抽象组件,方法也抽象化。如下所示:

    package com.wf.decorator.battercake.v2;
    
    /**
     * @ClassName AbstractBattercake
     * @Description 煎饼类,抽象顶层组件
     * @Author wf
     * @Date 2020/5/22 10:18
     * @Version 1.0
     */
    public abstract class AbstractBattercake {
        protected abstract String getMsg();
    
        public abstract int getPrice();
    }

    【2】具体化抽象组件

      提供一个基本的功能。

    package com.wf.decorator.battercake.v2;
    
    /**
     * @ClassName BaseBattercake
     * @Description 具体化煎饼功能
     * @Author wf
     * @Date 2020/5/22 10:50
     * @Version 1.0
     */
    public class BaseBattercake extends AbstractBattercake {
        @Override
        protected String getMsg() {
            return "这是一个煎饼";
        }
    
        @Override
        public int getPrice() {
            return 5;
        }
    }

    【3】提供一个装饰器的抽象接口

    package com.wf.decorator.battercake.v2;
    
    /**
     * @ClassName BattercakeDecorator
     * @Description 顶层装饰器
     * @Author wf
     * @Date 2020/5/22 10:53
     * @Version 1.0
     */
    public abstract class BattercakeDecorator extends AbstractBattercake {
        private AbstractBattercake battercake;
    
        public BattercakeDecorator(AbstractBattercake battercake) {
            this.battercake = battercake;
        }
    
        @Override
        protected String getMsg() {
            return this.battercake.getMsg();
        }
    
        @Override
        public int getPrice() {
            return this.battercake.getPrice();
        }
    }

    说明:

      这个顶层装饰器很重要,必须要组合引用抽象组件。通过构造器封装。

      实现方法,调用父类方法。

    【4】创建装饰器子类实现

    1.加蛋煎饼装饰器

    package com.wf.decorator.battercake.v2;
    
    /**
     * @ClassName EggDecorator
     * @Description 加蛋装饰器
     * @Author wf
     * @Date 2020/5/22 10:59
     * @Version 1.0
     */
    public class EggDecorator extends BattercakeDecorator {
        public EggDecorator(AbstractBattercake battercake) {
            super(battercake);
        }
    
        @Override
        protected String getMsg() {
            return super.getMsg() +",外加一个鸡蛋";
        }
    
        @Override
        public int getPrice() {
            return super.getPrice() + 1;
        }
    }

    2.加香肠装饰器

    package com.wf.decorator.battercake.v2;
    
    /**
     * @ClassName SausageDecorator
     * @Description 加香肠装饰器
     * @Author wf
     * @Date 2020/5/22 11:11
     * @Version 1.0
     */
    public class SausageDecorator extends BattercakeDecorator{
        public SausageDecorator(AbstractBattercake battercake) {
            super(battercake);
        }
    
        @Override
        protected String getMsg() {
            return super.getMsg()+",再加一根香肠";
        }
    
        @Override
        public int getPrice() {
            return super.getPrice() + 2;
        }
    }
    【5】客户端代码
    package com.wf.decorator.battercake.v2;
    /**
     * @ClassName Client
     * @Description 客户端调用
     * @Author wf
     * @Date 2020/5/22 11:16
     * @Version 1.0
     */
    public class Client {
        public static void main(String[] args) {
            AbstractBattercake battercake = new BaseBattercake();
            System.out.println(battercake.getMsg() +",总价是:"+battercake.getPrice());
    
            //加鸡蛋
            battercake = new EggDecorator(battercake);
            System.out.println(battercake.getMsg() +",总价是:"+battercake.getPrice());
    
            //加2个鸡蛋
            battercake = new EggDecorator(battercake);
            System.out.println(battercake.getMsg() +",总价是:"+battercake.getPrice());
    
            //加香肠
            battercake = new SausageDecorator(battercake);
            System.out.println(battercake.getMsg() +",总价是:"+battercake.getPrice());
        }
    }

    测试结果:

     说明:

      装饰器可以实现,动态增强的作用。

    4.项目实战需求应用

      假设开发了一个系统,系统各方面功能都不错。使用log4j和sl4j做日志处理,但是打印的字符串,太难解析。

    希望日志输出格式,进行一个调整,输出json格式

      但是,不希望去修改原来的代码,如果使用继承的话,会改变原有代码的功能。

      所以,选择使用装饰器模式,处理日志输出格式调整需求。

    【1】.引入maven依赖
    【2】测试类打印日志
    package com.wf.decorator.logger;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * @ClassName Test
     * @Description 测试类
     * @Author wf
     * @Date 2020/5/22 11:35
     * @Version 1.0
     */
    public class Test {
        private static final Logger logger = LoggerFactory.getLogger(Test.class);
    
        public static void main(String[] args) {
            logger.error("系统错误");
        }
    }

    测试结果如下:

    说明:

      控制台成功。打印日志。是以字符串的形式,不方便解析。希望打印成json格式。

      根据装饰器模式,需要定义顶层抽象接口,日志处理框架是Logger就是这个顶层抽象接口。下面就是定义具体的Logger实现。

    【3】定义Logger日志处理装饰器
    package com.wf.decorator.logger;
    
    import org.slf4j.Logger;
    import org.slf4j.Marker;
    
    /**
     * @ClassName LoggerDecorator
     * @Description 日志装饰器抽象接口
     * @Author wf
     * @Date 2020/5/22 12:48
     * @Version 1.0
     */
    public class LoggerDecorator implements Logger {
        protected Logger logger;
    
        public LoggerDecorator(Logger logger) {
            this.logger = logger;
        }
    
        @Override
        public String getName() {
            return null;
        }
    
        @Override
        public boolean isTraceEnabled() {
            return false;
        }
    
        @Override
        public void trace(String s) {
    
        }
    
        @Override
        public void trace(String s, Object o) {
    
        }
    
        @Override
        public void trace(String s, Object o, Object o1) {
    
        }
    
        @Override
        public void trace(String s, Object... objects) {
    
        }
    
        @Override
        public void trace(String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isTraceEnabled(Marker marker) {
            return false;
        }
    
        @Override
        public void trace(Marker marker, String s) {
    
        }
    
        @Override
        public void trace(Marker marker, String s, Object o) {
    
        }
    
        @Override
        public void trace(Marker marker, String s, Object o, Object o1) {
    
        }
    
        @Override
        public void trace(Marker marker, String s, Object... objects) {
    
        }
    
        @Override
        public void trace(Marker marker, String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isDebugEnabled() {
            return false;
        }
    
        @Override
        public void debug(String s) {
    
        }
    
        @Override
        public void debug(String s, Object o) {
    
        }
    
        @Override
        public void debug(String s, Object o, Object o1) {
    
        }
    
        @Override
        public void debug(String s, Object... objects) {
    
        }
    
        @Override
        public void debug(String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isDebugEnabled(Marker marker) {
            return false;
        }
    
        @Override
        public void debug(Marker marker, String s) {
    
        }
    
        @Override
        public void debug(Marker marker, String s, Object o) {
    
        }
    
        @Override
        public void debug(Marker marker, String s, Object o, Object o1) {
    
        }
    
        @Override
        public void debug(Marker marker, String s, Object... objects) {
    
        }
    
        @Override
        public void debug(Marker marker, String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isInfoEnabled() {
            return false;
        }
    
        @Override
        public void info(String s) {
    
        }
    
        @Override
        public void info(String s, Object o) {
    
        }
    
        @Override
        public void info(String s, Object o, Object o1) {
    
        }
    
        @Override
        public void info(String s, Object... objects) {
    
        }
    
        @Override
        public void info(String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isInfoEnabled(Marker marker) {
            return false;
        }
    
        @Override
        public void info(Marker marker, String s) {
    
        }
    
        @Override
        public void info(Marker marker, String s, Object o) {
    
        }
    
        @Override
        public void info(Marker marker, String s, Object o, Object o1) {
    
        }
    
        @Override
        public void info(Marker marker, String s, Object... objects) {
    
        }
    
        @Override
        public void info(Marker marker, String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isWarnEnabled() {
            return false;
        }
    
        @Override
        public void warn(String s) {
    
        }
    
        @Override
        public void warn(String s, Object o) {
    
        }
    
        @Override
        public void warn(String s, Object... objects) {
    
        }
    
        @Override
        public void warn(String s, Object o, Object o1) {
    
        }
    
        @Override
        public void warn(String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isWarnEnabled(Marker marker) {
            return false;
        }
    
        @Override
        public void warn(Marker marker, String s) {
    
        }
    
        @Override
        public void warn(Marker marker, String s, Object o) {
    
        }
    
        @Override
        public void warn(Marker marker, String s, Object o, Object o1) {
    
        }
    
        @Override
        public void warn(Marker marker, String s, Object... objects) {
    
        }
    
        @Override
        public void warn(Marker marker, String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isErrorEnabled() {
            return false;
        }
    
        @Override
        public void error(String s) {
    
        }
    
        @Override
        public void error(String s, Object o) {
    
        }
    
        @Override
        public void error(String s, Object o, Object o1) {
    
        }
    
        @Override
        public void error(String s, Object... objects) {
    
        }
    
        @Override
        public void error(String s, Throwable throwable) {
    
        }
    
        @Override
        public boolean isErrorEnabled(Marker marker) {
            return false;
        }
    
        @Override
        public void error(Marker marker, String s) {
    
        }
    
        @Override
        public void error(Marker marker, String s, Object o) {
    
        }
    
        @Override
        public void error(Marker marker, String s, Object o, Object o1) {
    
        }
    
        @Override
        public void error(Marker marker, String s, Object... objects) {
    
        }
    
        @Override
        public void error(Marker marker, String s, Throwable throwable) {
    
        }
    }
    【4】实现装饰器
    package com.wf.decorator.logger;
    
    import com.alibaba.fastjson.JSONObject;
    import org.slf4j.Logger;
    
    import java.util.Arrays;
    
    /**
     * @ClassName JsonLogger
     * @Description 输出json格式的日志组件实现
     * @Author wf
     * @Date 2020/5/22 12:46
     * @Version 1.0
     */
    public class JsonLogger extends LoggerDecorator {
    
        public JsonLogger(Logger logger) {
            super(logger);
        }
    
        @Override
        public void error(String s) {
            JSONObject result = newJSONObject();
            result.put("msg",s);
            logger.info(result.toString());
        }
    
        @Override
        public void info(String s) {
            JSONObject result = newJSONObject();
            result.put("msg",s);
            logger.info(result.toString());
        }
        public void error(Exception e){
            JSONObject result = newJSONObject();
            result.put("exception",e.getClass().getName());
            String trace = Arrays.toString(e.getStackTrace());
            result.put("exTrace",trace);
            logger.info(result.toString());
    
        }
        private JSONObject newJSONObject(){
            return new JSONObject();
        }
    }

    注意:

      这里引入JSONObject工具,需要添加依赖:

    <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>fastjson</artifactId>
          <version>1.2.32</version>
        </dependency>
    【5】定义Logger工厂
    package com.wf.decorator.logger;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * @ClassName JsonLoggerFactory
     * @Description 创建Logger的工厂类
     * @Author wf
     * @Date 2020/5/22 13:02
     * @Version 1.0
     */
    public class JsonLoggerFactory {
        public static JsonLogger getLogger(Class clazz){
            Logger logger = LoggerFactory.getLogger(clazz);
            return new JsonLogger(logger);
        }
    }
    主要是为了生成JsonLogger实例。
    【6】测试类修改
    package com.wf.decorator.logger;
    
    import org.slf4j.Logger;
    
    /**
     * @ClassName Test
     * @Description 测试类
     * @Author wf
     * @Date 2020/5/22 11:35
     * @Version 1.0
     */
    public class Test {
        //private static final Logger logger = LoggerFactory.getLogger(Test.class);
        private static final Logger logger = JsonLoggerFactory.getLogger(Test.class);
    
        public static void main(String[] args) {
            logger.error("系统错误");
        }
    }
    测试结果如下:

     功能完成。

    【7】查看系统类图

    1.6.2.3.装饰器模式总结

    1.装饰器模式在源码中应用

    IO流中字节流,封装成字符流,缓冲流。 

    package com.wf.decorator.logger;
    
    import org.slf4j.Logger;
    
    import java.io.*;
    
    /**
     * @ClassName Test
     * @Description 测试类
     * @Author wf
     * @Date 2020/5/22 11:35
     * @Version 1.0
     */
    public class Test {
        //private static final Logger logger = LoggerFactory.getLogger(Test.class);
        private static final Logger logger = JsonLoggerFactory.getLogger(Test.class);
    
        public static void main(String[] args) {
            logger.error("系统错误");
    
            //IO流中装饰器模式应用
            try {
                InputStream in = new FileInputStream("");
    
                BufferedInputStream bis = new BufferedInputStream(in);
    
                bis.read();
                bis.close();
    
                BufferedReader br = new BufferedReader(new FileReader(""));
                br.readLine();
    
                BufferedReader bs = new BufferedReader(new StringReader(""));
                bs.readLine();
    
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(String.valueOf(e));
            }
        }
    }
    2.装饰器模式与代理模式的对比

    装饰器模式:

      是一种特殊的静态代理模式。

      强调自身功能的扩展透明【用户知道扩展细节】的扩展,可动态定制的扩展。

    代理模式:

      强调代理过程的控制

    3.装饰器模式的优缺点

    优点:

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

      通过使用不同的装饰类,以及这些装饰类的排列组合,可实现更为强大的功能。 

      装饰器完全遵循开闭原则

    缺点:

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

      动态装饰时,多层装饰会比较复杂。客户端调用复杂。

    1.6.2.4.相关补充

    1.列举3~5个使用门面模式的应用场景

    1.项目中使用不同分层,如:mvc模式,三层架构。

    2.分布式rpc调用时,通过门面模式将不同子系统提供服务整合。

    3.日志框架将不同的日志级别,debug,info,warn,errror通过一个接口对外暴露。

    4.web开发中Controller类。

    2.使用装饰者模式实现一个可以根据权限动态扩展功能的导航条展示。
    【1】需求分析

    社区网站首页,导航条展示所有条目有:

    1.问答

    2.文章

    3.精品课

    4.冒泡

    5.商城

    6.作业

    7.题库

    8.成长墙

    9.用户管理 

    用户权限:

    A.未登录 

    B.已登录普通用户

    C.已登录会员vip用户

    D.管理员

    根据不同权限,展示导航条目有:

    A ->1,2,3,4,5

    B->1,2,3,4,5,7

    C->1,2,3,4,5,7,6,8

    D->1,2,3,4,5,7,6,8,9

    可以认为,前5种展示条目,所有权限都可以展示,处理成初始化时,组件具备基本功能。

    而后面的每一种展示条目,分别设计成一个装饰器类。

    客户端根据不同权限,组合装饰器功能,完成导航条的展示设计。

    为此,也方便以后出现其他展示条目,进行动态扩展。

    【2】设计类图

    A.用户权限设计

     

     B.导航条展示设置

     C.系统类图

    【3】代码编写

    1.导航条展示组件顶层抽象接口

    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName AbstractNavigationBar
     * @Description 导航条抽象顶层接口
     * @Author wf
     * @Date 2020/5/22 14:48
     * @Version 1.0
     */
    public abstract class AbstractNavigationBar {
        public abstract String showItems();
    }

    2.组件基本功能实现

    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName DefaultNavigationBar
     * @Description 组件默认实现
     * @Author wf
     * @Date 2020/5/22 14:52
     * @Version 1.0
     */
    public class DefaultNavigationBar extends AbstractNavigationBar {
        @Override
        public String showItems() {
            return "问答,文章,精品课,冒泡,商城";
        }
    }

    3.定义装饰器抽象接口

    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName NavigationBarDecorator
     * @Description 导航条条目展示装饰器抽象接口
     * @Author wf
     * @Date 2020/5/22 14:55
     * @Version 1.0
     */
    public abstract class NavigationBarDecorator extends AbstractNavigationBar{
        private AbstractNavigationBar navigationBar;
    
        public NavigationBarDecorator(AbstractNavigationBar navigationBar) {
            this.navigationBar = navigationBar;
        }
    
        @Override
        public String showItems() {
            return this.navigationBar.showItems();
        }
    }

    4.定义3个装饰器子类

    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName LoginDecorator
     * @Description 登录普通用户装饰器
     * @Author wf
     * @Date 2020/5/22 14:58
     * @Version 1.0
     */
    public class LoginDecorator extends NavigationBarDecorator {
        public LoginDecorator(AbstractNavigationBar navigationBar) {
            super(navigationBar);
        }
    
        @Override
        public String showItems() {
           return super.showItems() +",题库";
        }
    }
    
    package com.wf.decorator.navigationbar;
    
    import sun.plugin2.message.ShowDocumentMessage;
    
    /**
     * @ClassName VipDecorator
     * @Description 已登录会员用户,导航条装饰器
     * @Author wf
     * @Date 2020/5/22 15:00
     * @Version 1.0
     */
    public class VipDecorator extends NavigationBarDecorator {
        public VipDecorator(AbstractNavigationBar navigationBar) {
            super(navigationBar);
        }
    
        @Override
        public String showItems() {
            return super.showItems() +",作业,成长墙";
        }
    }
    
    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName ManagerDecorator
     * @Description 管理员装饰器
     * @Author wf
     * @Date 2020/5/22 15:02
     * @Version 1.0
     */
    public class ManagerDecorator extends NavigationBarDecorator {
        public ManagerDecorator(AbstractNavigationBar navigationBar) {
            super(navigationBar);
        }
    
        @Override
        public String showItems() {
            return super.showItems()+",用户管理";
        }
    }

    5.定义用户权限处理抽象接口

    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName IPermission
     * @Description 权限顶层接口
     * @Author wf
     * @Date 2020/5/22 15:25
     * @Version 1.0
     */
    public abstract class AbstractPermission {
        protected AbstractNavigationBar navigationBar;
    
        protected void showItems(){
            System.out.println(navigationBar.showItems());
        }
    }

    6.定义四种不同权限处理实现类

    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName Visitor
     * @Description 未登录用户权限,访问权限
     * @Author wf
     * @Date 2020/5/22 15:29
     * @Version 1.0
     */
    public class Visitor extends AbstractPermission {
    
        @Override
        protected void showItems() {
            navigationBar = new DefaultNavigationBar();
            super.showItems();
        }
    }
    
    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName LoginUser
     * @Description TODO
     * @Author wf
     * @Date 2020/5/22 15:36
     * @Version 1.0
     */
    public class LoginUser extends AbstractPermission {
    
        @Override
        protected void showItems() {
            navigationBar = new DefaultNavigationBar();
            navigationBar = new LoginDecorator(navigationBar);
            super.showItems();
        }
    }
    
    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName VipUser
     * @Description 已登录会员权限
     * @Author wf
     * @Date 2020/5/22 15:40
     * @Version 1.0
     */
    public class VipUser extends AbstractPermission {
    
        @Override
        protected void showItems() {
            navigationBar = new DefaultNavigationBar();
            navigationBar = new LoginDecorator(navigationBar);
            navigationBar = new VipDecorator(navigationBar);
            super.showItems();
        }
    }
    
    package com.wf.decorator.navigationbar;
    
    /**
     * @ClassName Admin
     * @Description 管理员权限
     * @Author wf
     * @Date 2020/5/22 15:42
     * @Version 1.0
     */
    public class Admin extends AbstractPermission {
    
        @Override
        protected void showItems() {
            navigationBar = new DefaultNavigationBar();
            navigationBar = new LoginDecorator(navigationBar);
            navigationBar = new VipDecorator(navigationBar);
            navigationBar = new ManagerDecorator(navigationBar);
            super.showItems();
        }
    }

    7.客户端调用

    package com.wf.decorator.navigationbar;
    
    import com.wf.decorator.general.Decorator;
    import org.omg.CORBA.NVList;
    
    /**
     * @ClassName Test
     * @Description 测试类
     * @Author wf
     * @Date 2020/5/22 15:06
     * @Version 1.0
     */
    public class Test {
        public static void main(String[] args) {
            AbstractPermission permission = new Visitor();
            permission.showItems();
    
            permission = new LoginUser();
            permission.showItems();
    
            permission = new VipUser();
            permission.showItems();
    
            permission = new Admin();
            permission.showItems();
    
        }
    }

    测试结果如下:

      

    附录:

    1.log4j结合slf4j输出日志到控制台

    1.1.maven引入依赖

     <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-api</artifactId>
          <version>1.7.25</version>
        </dependency>
    
        <dependency>
          <groupId>ch.qos.logback</groupId>
          <artifactId>logback-classic</artifactId>
          <version>1.2.3</version>
        </dependency>
  • 相关阅读:
    词根——rect
    6
    7
    5
    3
    4
    2
    1
    DBUtils
    Websocket
  • 原文地址:https://www.cnblogs.com/wfdespace/p/12925477.html
Copyright © 2020-2023  润新知