精华内容
下载资源
问答
  • 2021-06-18 11:05:07

    装饰器模式的优点

    1. 装饰器模式与继承关系的目的都是要扩展对象的功能,但是装饰器模式可以提供比继承更多的灵活性。当需要扩展多个功能时,装饰器模式只需要增加新的具体装饰类即可,而继承关系则需要继承原有类,再进行扩展,如果需要在不改变原有类的基础上继续扩展,则需要再次继承,这样代码耦合性比较高。
    2. 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
    3. 通过使用不同的具体装饰器类以及这些装饰器类的排列组合,可以创建出很多不同的组合。可以使用多个具体装饰类来装饰同一个对象。
    4. 具体构建类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰器类,在使用时再对其进行组合额,原有代码无线改变,符合“开闭原则”。
    更多相关内容
  • 设计模式-装饰器模式:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

    装饰器模式

    源码:https://github.com/GiraffePeng/design-patterns

    1、定义

    指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。
    通过这句话,我们可以知道装饰器模式不允许修改被装饰的类,如果要附加职责,需要进行拓展,符合开闭原则。
    然后按照单一职责原则,某一个对象只专注于干一件事,而如果要扩展其职能的话,不如想办法分离出一个类来“包装”这个对象,而这个扩展出的类则专注于实现扩展功能

    2、应用场景

    • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
    • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现。
    • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

    3、模式结构

    通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。下面来分析其基本结构和实现方法。

    模式的结构
    装饰模式主要包含以下角色。

    • 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
    • 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
    • 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
    • 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

    4、应用实例+与其他容器混淆模式对比

    4.1、登录实例(继承与装饰器的区别)

    我们拿登录来说,假如一个业务需求,需要实现普通的登录,第三方QQ登录,第三方微信登录。
    我们通常会怎么设计,我们会先创建一个登录接口,然后根据多态创建其不同的实现类来对应每个登录场景。
    按照上面的说法我们来创建一个登录接口。

    //声明登录接口
    public interface LoginService {
    	public void login();
    }
    

    根据不同的场景,我们创建不同的实现类,分别对应普通的登录,第三方QQ登录,第三方微信登录。

    //普通登录
    public class LoginBaseServiceImpl implements LoginService{
    
    	@Override
    	public void login() {
    		System.out.println("登录方法");
    	}
    }
    //微信登录
    public class LoginWechatServiceImpl implements LoginService{
    
    	@Override
    	public void login() {
    		System.out.println("微信登录方法");
    	}
    }
    //微信登录
    public class LoginWechatServiceImpl implements LoginService{
    
    	@Override
    	public void login() {
    		System.out.println("微信登录方法");
    	}
    }
    

    接下来我们有个新需求说,要在登录功能中加入一些新的逻辑处理或者新的结合登录的前置功能。‘
    根据开闭原则,对修改关闭对拓展开放,如果在不改动原有代码的基础上,我们如何去实现这个功能,应该怎么来写?
    通常我们会想到继承方式,使用继承来拓展父类的方法。

    4.1.1、继承实现父类的拓展

    既然要在所有的登录功能前做些处理,我们需要对每个场景下的登录实现来创建其子类来实现。
    创建各自的子类,分别对应普通的登录,第三方QQ登录,第三方微信登录。

    //普通登录子类
    public class LoginPrefixServiceImpl extends LoginBaseServiceImpl{
    
    	@Override
    	public void login() {
    		doSomething();
    		super.login();
    	}
    
    	public void doSomething() {
    		System.out.println("拓展一些方法");
    	}
    }
    //QQ登录子类
    public class LoginPrefixQQServiceImpl extends LoginQQServiceImpl{
    
    	@Override
    	public void login() {
    		doSomething();
    		super.login();
    	}
    
    	public void doSomething() {
    		System.out.println("拓展一些方法");
    	}
    }
    //微信登录子类
    public class LoginPrefixWechatServiceImpl extends LoginWechatServiceImpl{
    
    	@Override
    	public void login() {
    		doSomething();
    		super.login();
    	}
    
    	public void doSomething() {
    		System.out.println("拓展一些方法");
    	}
    }
    

    这时的类的结构就变成如下图所示:
    在这里插入图片描述
    ok,我们完成了这次需求的改动。随着业务的发展,又有新的需求来了,需要在登录的功能后加入逻辑处理或者结合登陆的后置功能,我们用继承怎么来写? 会按照上述的方式再去继承父类,变成下面这个样子。
    在这里插入图片描述
    那么好,需求又说了,我要结合以前的登录功能,在登录的前后都要加入相应的逻辑处理,且处理方式与之前的一致。即 新需求 = 前面实现的登录前逻辑处理 + 登录 + 前面实现的登录后逻辑处理。
    这时候我们用继承怎么来写,难道要继续创建每个场景下的子类吗。这样随着需求的变化,我们会用N多个子类,很不灵活。我们能不能把前置逻辑处理以及后置逻辑处理抽取为单独的模块,供这些登录场景使用呢?意思就是在登录场景中修饰它,为它动态的增加职责,而不是静态的通过继承来确认相互之间的关系。
    这时就引出的装饰器模式。下面我们来用装饰器来实现上述的需求场景。

    4.1.2 装饰器实现类的拓展

    根据上述的场景,抽象构件角色(LoginService)和具体构建角色(LoginBaseServiceImpl、LoginQQServiceImpl、LoginWechatServiceImpl)已经具备了,利用装饰器模式的话,我们还需要抽象装饰角色以及具体装饰角色。下面我们来创建抽象装饰角色.

    //装饰器 抽象装饰角色
    public abstract class AbstractLoginServiceImpl implements LoginService{
    
    	private LoginService loginService;
    
    	public AbstractLoginServiceImpl(LoginService loginService) {
    		super();
    		this.loginService = loginService;
    	}
    	
    	public void login() {
    		loginService.login();
    	}
    }
    

    根据上述需求,我们了解到,要在登陆的前后分别添加新的职责,我们按照抽象装饰角色来实现多个场景。

    //前置拓展类 具体抽象装饰角色
    public class DoPrefixLoginServiceImpl extends AbstractLoginServiceImpl{
    
    	public DoPrefixLoginServiceImpl(LoginService loginService) {
    		super(loginService);
    	}
    
    	public void login() {
    		doSomething();
    		super.login();
    	}
    
    	public void doSomething() {
    		System.out.println("在方法前拓展一些方法");
    	}
    }
    //后置拓展类 具体抽象装饰角色
    public class DoSuffixLoginServiceImpl extends AbstractLoginServiceImpl{
    
    	public DoSuffixLoginServiceImpl(LoginService loginService) {
    		super(loginService);
    	}
    
    	public void login() {
    		super.login();
    		doSomething();
    	}
    
    	public void doSomething() {
    		System.out.println("在方法后拓展一些方法");
    	}
    }
    

    这个时候我们来看下这个类图
    在这里插入图片描述
    创建测试类

    public class Test {
    
    	public static void main(String[] args) {
    		LoginService loginService = new LoginQQServiceImpl();
    		loginService.login();
    		System.out.println("---------");
    		
    		//在方法前拓展内容
    		LoginService doPrefixLoginService = new DoPrefixLoginServiceImpl(loginService);
    		doPrefixLoginService.login();
    		
    		System.out.println("---------");
    		
    		//想在方法后拓展内容
    		LoginService doSuffixLoginService = new DoSuffixLoginServiceImpl(loginService);
    		doSuffixLoginService.login();
    		
    		System.out.println("---------");
    		//即想在方法前拓展内容 ,又想在方法后拓展内容
    		LoginService doSuffixAndPrefixLoginService = new DoSuffixLoginServiceImpl(doPrefixLoginService);
    		doSuffixAndPrefixLoginService.login();
    	}
    }
    

    打印结果:

    QQ登陆方法
    ---------
    在方法前拓展一些方法
    QQ登陆方法
    ---------
    QQ登陆方法
    在方法后拓展一些方法
    ---------
    在方法前拓展一些方法
    QQ登陆方法
    在方法后拓展一些方法
    

    这个时候不管需求如何变动,我们都可以通过抽象装饰器为基础,来动态的定义新的子类来满足各个场景下的需求。

    4.1.3 继承与装饰器总结

    • 装饰器模式比继承要灵活。避免了继承体系臃肿
    • 装饰器模式降低了类于类之间的关系。
    • 你要说用装饰器实现的功能,继承能否实现,我只能说能,但是在代码的结构层次上来说,装饰器模式比继承灵活了很多。
    • 装饰模式与继承关系的目的都是要拓展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者“除掉”一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了
    • 看上面的测试类可以知道:通过不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出更多不同行为的组合。

    4.2、装饰器与适配器的区别

    这里不做过多实例代码对比,可参考上一篇文章代码实例做对比:《八、适配器模式(类适配器、对象适配器、双向适配器)[AdapterPattern]》
    装饰者和适配器模式都是包装模式(Wrapper Pattern),装饰者也是一种特殊的代理模式.

    装饰者模式适配器模式
    形式是一种非常特别的适配器模式没有层级关系,装饰器模式有层级关系
    定义装饰者和被装饰者都实现同一个接口,主要目的是为了拓展之后依旧保持OOP关系适配器和被适配者没有必然的联系,通常采用继承或代理的形式进行包装
    关系满足 is-a 的关系满足 has-a 的关系
    功能注重覆盖、扩展注重兼容、转换
    设计前置考虑后置考虑

    4.3、装饰器与代理模式区别

    又有小伙伴说了,这装饰器模式与代理模式好像啊,都是在方法的前后增加附加的代码块来完成某个功能的实现。
    既然把他们划分为两个设计模式,就当然会有区别。

    装饰者模式代理模式
    关注点关注于在一个对象上动态的添加方法关注于控制对对象的访问
    原有对象的持有方式当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。用代理模式,代理类可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例
    注重点注重对对象功能的扩展,它不关心外界如何调用,只注重对对象功能的加强,装饰后还是对象本身注重对对象某一功能的流程把控和辅助。它可以控制对象做某些事,偏重因自己无法完成或自己无需关心,需要他人干涉事件流程,更多的是对对象的控制重心是为了借用对象的功能完成某一流程,而非对象功能如何
    客户端调用A类是原始功能的类, B是装饰模式中对A类的扩展之后的类,使用装饰模式, 用户更关系的是B的功能(包含A的原始功能)A类是原始功能的类,C是代理模式中对A类的扩展,使用代理模式,用户更关心A的功能。并不关心C的功能

    对于代理类,如何调用对象的某一功能是思考重点,而不需要兼顾对象的所有功能; 对于装饰类,如何扩展对象的某一功能是思考重点,同时也需要兼顾对象的其它功能,因为再怎么装饰,本质也是对象本身,要担负起对象应有的职责。
    尽管他们在写法上会有很多相似的地方,但所表达的意思缺失完全不同的。大家只要记住一句话:代理模式是控制对象的访问,装饰器是增强对象的功能。
    针对用户或者客户端来说

    • 调用装饰器模式,它需要知道原有对象的功能以及装饰器类相应增强的功能,并且装饰器类里有原有对象的所有方法。
    • 调用代理模式,它可能并不知道原有对象本身,它只知道代理类的功能,并且代理类中只持有原有对象的部分方法来进行代理加强。

    5、装饰器在源码中的应用

    由于JAVA I/O库需要很多性能的各种组合,如果这些性能都是用继承的方法实现的,那么每一种组合都需要一种类,这样就会造成大量性能重复的类出现。而如果采用装饰模式,那么类的数目就会大大减少,性能的重复也可以减至最小。因此装饰模式是JAVA I/O库的基本模式。
    以InputStream为例,看下类图
    在这里插入图片描述

    5.1、示例

    public class StreamTest {
    
    	public static void main(String[] args) {
    		DataInputStream dis = null;
            try {
                dis = new DataInputStream(
                        new BufferedInputStream(
                                new FileInputStream("23.txt")
                                )
                        );
                byte[] bytes = new byte[dis.available()];
                dis.read(bytes);
                String content = new String(bytes);
                System.out.println(content);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    	}
    }
    

    观察上面的代码,会发现最里层是一个FileInputStream对象,然后把它传递给一个BufferedInputStream对象,经过BufferedInputStream对象处理后,再将处理后的对象传递给DataInputStream对象进行处理。这个过程,其实就是装饰器的组装过程,FileInputStream对象相当于原始的被装饰的对象,而BufferedInputStream对象和DataInputStream对象则相当于装饰器。

    6、优缺点

    装饰(Decorator)模式的主要优点有:

    • 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
    • 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合

    其主要缺点是:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。

    展开全文
  • 装饰器模式

    千次阅读 2020-12-12 21:08:13
    所有这些都可以釆用装饰模式来实现。 一、装饰模式 1、装饰模式的定义 装饰模式(Decorator Pattern)的定义: 指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它...

    在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰模式来实现。

    一、装饰器模式

    1、装饰器模式的定义

    装饰器模式(Decorator Pattern),又叫作包装器模式(Wrapper Pattern):

    指在不改变原有对象结构的基础情况下,动态地给该对象增加一些额外功能的职责。装饰器模式相比生成子类更加灵活。它属于对象结构型模式。

    装饰模式和代理模式的功能是雷同的,两者区别是:

    • 装饰器模式强调自身功能的扩展,是代理模式的一个特殊应用。
    • 代理模式强调对代理过程的控制。

    2、装饰器模式的结构

    通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。
    如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。

    下面来分析其基本结构和实现方法。

    (1)模式的结构

    装饰模式主要包含四个角色。

    • 抽象构件(Component): 可以是一个接口或者抽象类,充当被装饰类的原始对象,规定了被装饰类的行为。
    • 具体构件(ConcreteComponent): 实现/继承 Component的一个具体对象,即被装饰对象。通过装饰角色为其添加一些职责。
    • 抽象装饰器(Decorator): 实现/继承 Component。通用的 ConcreteComponent的装饰列,其内部必然有一个属性指向 Component,主要是可以通过其子类扩展具体组件的功能。
    • 具体装饰器(ConcreteDecorator): Decorator的具体实现类,并给具体构件对象添加附加的责任,一般为其特有的功能。

    装饰器模式j角色分配符合设计模式的里氏替换原则、依赖倒置原则,从而使得其具备很强的扩展性,最终满足开闭原则。

    (2)结构图如下:(图来自网络)
    在这里插入图片描述

    3、优缺点

    主要优点:

    • 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
    • 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
    • 装饰器模式完全遵守开闭原则

    主要缺点:

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

    4、使用场景

    • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。
    • 当对象的功能要求可以动态地添加,也可以再动态地被撤销时。
    • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现。

    在框架源码中使用也很广泛,比如:

    • JDK中的处理流 IO中包装流类等
    • Spring 中处理事务缓存的 TransactionAwareCacheDecorator类
    • Mybatis 中处理缓存设计的 Cache类等

    二、模式的通用实现

    代码如下:

    public class DecoratorPattern {
        public static void main(String[] args) {
            Component p = new ConcreteComponent();
            p.operation();
            System.out.println("---------------装饰之后------------------");
            Component d = new ConcreteDecorator(p);
            d.operation();
        }
    }
    
    //抽象构件
    interface Component {
        public void operation();
    }
    
    //具体构件
    class ConcreteComponent implements Component {
        public ConcreteComponent() {
            System.out.println("创建具体构件角色");
        }
    
        // 相应的功能处理
        @Override
        public void operation() {
            System.out.println("调用具体构件角色的方法operation()");
        }
    }
    
    //抽象装饰器
    class Decorator implements Component {
        // 持有的组件对象
        private Component component;
    
        public Decorator(Component component) {
            this.component = component;
        }
    
        @Override
        public void operation() {
            // 处理前后可以加一些附加功能
            component.operation();
        }
    }
    
    //具体装饰器
    class ConcreteDecorator extends Decorator {
        public ConcreteDecorator(Component component) {
            super(component);
        }
    
        @Override
        public void operation() {
            // 在处理父类的方法时,可以在处理前后可以加一些附加功能
            // 如果不调用父类的方法,表示完全改写方法,实现新功能
            super.operation();
            addedFunction();
        }
    
        public void addedFunction() {
            System.out.println("为具体构件角色增加额外的功能addedFunction()");
        }
    }
    

    三、模式的应用实例

    用一个卖煎饼果子的例子来说明。

    • 原味版:煎饼果子,总价格:5
    • 豪华版:辅料可自由搭配

    1、抽象构件(Component)

    public abstract class Battercake {
    
        protected abstract  String  getMessage();
    
        protected abstract int getPrice();
    }
    

    2、具体构件(ConcreteComponent)

    public class BaseBattercake extends Battercake{
    
        @Override
        protected String getMessage() {
            return "煎饼果子";
        }
    
        @Override
        protected int getPrice() {
            return 5;
        }
    }
    

    3、抽象装饰器(Decorator)

    public abstract class BattercakeDecorator extends Battercake{
        // 静态代理,委托
        private Battercake battercake;
    
        public BattercakeDecorator(Battercake battercake) {
            this.battercake = battercake;
        }
    
        @Override
        protected String getMessage() {
            return this.battercake.getMessage();
        }
    
        @Override
        protected int getPrice() {
            return this.battercake.getPrice();
        }
    
        // 可以加额外功能方法
        protected abstract void addedFunction();
    }
    

    4、具体装饰器(ConcreteDecorator)
    这里给定三种辅料可供选择

    • 鸡蛋
    public class EggDecorator extends BattercakeDecorator {
    
        public EggDecorator(Battercake battercake) {
            super(battercake);
        }
    
        @Override
        protected String getMessage() {
            return super.getMessage() + " + 1个鸡蛋";
        }
    
        @Override
        protected int getPrice() {
            return super.getPrice() + 2;
        }
    
        @Override
        protected void addedFunction() {
    
        }
    
        // 可以加其特有的功能方法
    }
    
    • 香肠
    public class SausageDecorator extends BattercakeDecorator{
    
        public SausageDecorator(Battercake battercake) {
            super(battercake);
        }
    
        @Override
        protected String getMessage() {
            return super.getMessage() + " + 一个香肠";
        }
    
        @Override
        protected int getPrice() {
            return super.getPrice() + 4;
        }
    
        @Override
        protected void addedFunction() {
    
        }
        // 可以加其特有的功能方法
    }
    
    • 另类
    public class OtherDecorator extends BattercakeDecorator{
        public OtherDecorator(Battercake battercake) {
            super(battercake);
        }
    
        @Override
        protected String getMessage() {
            return message();
        }
    
        @Override
        protected int getPrice() {
            return price();
        }
    
        @Override
        protected void addedFunction() {
    
        }
    
        // 可以加其特有的功能方法
        private String message(){
            return "老板,啥也不要,来根大葱";
        }
        private int price(){
            return 5;
        }
    }
    

    5、测试

    public class Test {
        public static void main(String[] args) {
            System.out.println("===来一个基础版煎饼果子===");
            Battercake battercake = new BaseBattercake();
            System.out.println(battercake.getMessage() + ",总价格:" + battercake.getPrice() + "元。");
    
            System.out.println("===来一个套餐A煎饼果子===");
            battercake = new EggDecorator(battercake);
            System.out.println(battercake.getMessage() + ",总价格:" + battercake.getPrice() + "元。");
    
            System.out.println("===来一个套餐A+B煎饼果子===");
            battercake = new SausageDecorator(battercake);
            System.out.println(battercake.getMessage() + ",总价格:" + battercake.getPrice() + "元。");
    
    
            System.out.println("===屌丝买煎饼果子===");
            Battercake battercake2 = new BaseBattercake();
            battercake2 = new OtherDecorator(battercake2);
            System.out.println(battercake2.getMessage() + ",总价格:" + battercake2.getPrice() + "元。");
        }
    }
    

    在这里插入图片描述

    四、装饰模式的扩展

    装饰模式所包含的 4 个角色不是任何时候都要存在的,在有些应用环境下模式是可以简化的,有时候抽象装饰器是可有可无的,如以下两种情况。(图来自网络)

    1、只有一个具体装饰器,这样就不需要抽象装饰器,其结构图如下:
    在这里插入图片描述
    2、只有一个具体构件,这样就不需要抽象构件,抽象装饰者可以直接继承具体构件,其结构图如下:
    在这里插入图片描述
    3、只有一个具体构件和一个具体装饰者,这样抽象角色都不需要了,具体装饰者直接继承集体构件就可以了
    在这里插入图片描述

    参考文章:

    —— Stay Hungry. Stay Foolish. 求知若饥,虚心若愚。

    展开全文
  • JS-装饰器模式

    2019-10-08 15:02:57
    继承相比装饰者是一种更轻便灵活的做法。 这里不要和之前讲的代理模式搞混,代理模式主要是对直接访问本体不方便或者不符合需要的时候提供一个代替者;装饰模式 主要是为对象动态添加一些行为 优点 可以...

    介绍

    在不改变类或对象自身的基础上,在程序的运行期间动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。

    这里不要和之前讲的代理模式搞混,代理模式主要是对直接访问本体不方便或者不符合需要的时候提供一个代替者;装饰者模式

    主要是为对象动态添加一些行为

    优点

    可以动态的给某个对象添加额外的职责,而不会影响从这个类中派生的其它对象。

    实现

    老规矩举个栗子来解释一下:童年经典游戏魂斗罗,一出场默认的是普通子弹,后面根据吃的弹发射对应的子弹,比如散弹、激光弹等等,但是原有的普通子弹是一直有的

    var bullet = {
    	fire: function(){
    		console.log('发射普通子弹');
    	}
    }
    bullet.fire(); // '发射普通子弹'
    
    //吃了散弹buff
    var fire1 = bullet.fire;
    var shotBullet = function() {
    	console.log('发射散弹');
    };
    bullet.fire = function () {
    	fire1();
    	shotBullet();
    };
    bullet.fire(); // '发射普通子弹' '发射散弹'
    
    
    //吃了散弹buff
    var fire2 = bullet.fire;
    var laserBullet = function() {
    	console.log('发射激光弹');
    };
    bullet.fire = function () {
    	fire2();
    	laserBullet();
    };
    bullet.fire(); // '发射普通子弹' '发射激光弹'

    ES7的decorator

    在ES7中提供了一种类似于java注解的语法糖decorator来实现装饰器模式。decorator的实现依赖于ES5的Object.defineProperty方法来进行扩展和封装的。装饰器是一种函数,写法是 @+函数名

    @testable
    class MyTestableClass {
      // ...
    }
    
    function testable(target) {
      target.isTestable = true;
    }
    
    MyTestableClass.isTestable // true
    
    
    @decorator
    class A {}
    
    // 等同于
    class A {}
    A = decorator(A) || A;

    上面代码中,@testable就是一个装饰器。它修改了MyTestableClass这个类的行为,为它加上了静态属性isTestabletestable函数的参数targetMyTestableClass类本身。

    function mixins(...list) {
       return function(target) {
          Object.assign(target.prototype, ...list)
       }
    }
    
    const Foo = {
        foo() {
            console.log('foo');
        }
    }
    
    @mixins(Foo)
    class MyClass { }
    
    let obj = new MyClass();
    obj.foo(); //foo
    

    上例中,Foo作为list的实参,MyClass作为 target的实参,最终实现将Foo的所有原型方法(foo)装饰到 MyClass类上,成为了MyClass的方法。最终代码的运行结果是执行foo()

    除了可以装饰类,也可以装饰类的属性

    function readonly(target , name , descriptor) {
      descriptor.writable = false;
    }
    
    class Person {
        constructor() {
            this.first = '周';
            this.last = '杰伦';
        }
    
        @readonly
        name() {
            return `${this.first}${this.last}`
        }
    }
    
    const p = new Person();
    console.log(p.name());  // ‘周杰伦’
    
    // 试图修改name:
    p.name = function() {
        return true;
    }
    // Uncaught TypeError:Cannot assign to read only property 'name' of object '#<Person>'
    

    在上栗中,由于decorator的实现依赖于Object.defineProperty,所以参数和用法也一致,接收三个参数targetnamedescriptor

    展开全文
  • 关于装饰器设计模式优点和缺点,GOF中这样描述: 优点 比静态继承更灵活,与对象的静态继承(多重继承)相比, Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和...
  • 设计模式:有助于提高代码的复用性和可维护性 常用的12种设计模式 工厂模式 单例模式 ...就增加功能来说,装饰器模式相比生成子类更为灵活。 主要解决 一般的,我们为了扩展一个类经常使用继承方式实
  • 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 这种模式创建了一个装饰类,用来包装原有的类,并在保持类...
  • 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。...就增加功能来说,装饰器模式相比生成子类更为灵活。 主要解决:一般的,我们为了扩展一个类经常使用继
  • 装饰器模式的优缺点优点缺点 一、装饰器模式是什么? 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 ...
  • 装饰器模式 —— 来源网络介绍 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,...就增加功能来说,装饰器模式相比生成子类更为灵活。 .
  • 点击上方“前端开发博客”,选择“星标”回复“签到”,每日领红包来源 |http://www.fly63.com/article/detial/10063设计模式简介:设计模式是可重用的...
  • JavaScript设计模式总汇

    2021-05-30 00:19:08
    来源 |http://www.fly63.com/article/detial/10063设计模式简介:设计模式是可重用的用于解决软件设计中一般问题的方案。设计模式如此让人着迷,以至在任...
  • JS设计模式与开发实践

    千次阅读 2018-09-01 13:34:12
    最近开始看曾探的《JavaScript设计模式与开发实践》一书,仅以此篇博客记录学习内容。 设计模式的定义是:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。通俗一点说,设计模式是在某种场合下针对...
  • 讲设计模式的书很多,但是专讲js设计模式的书不多,比较著名的就是曾琛老师的《javascript设计模式与开发实践》,里面讲了14种javascript设计模式以及这些设计模式所遵循的几大编码原则。 无意中发现了百度张容铭的...
  • 就增加功能来说,装饰器模式相比生成子类更为灵活。 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。 何时使用:在不想增加很多...
  • JavaScript中的经典设计模式详解
  • (一)补充重要知识点: (一)this、call和apply ...(3)构造调用-------通常指向返回的对象,但是如果构造显示地返回了一个object类型的对象,那么此次运算结果最终会返回这个对象。 ...
  • 装饰器模式 对客户透明的方式动态地给一个对象附加上更多的责任,同时又不改变其结构。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。 装饰器要素 1.抽象构件(Component)角色:给出一个抽象接口...
  • 设计模式总结设计原则和编程技巧单一职责原则(SRP)定义设计模式中体现何时应该分离职责SRP 原则的优缺点最少知识原则(LKP)- 迪米特法则定义设计模式中体现封装在最少知识原则中的体现开放-封闭原则定义最佳实践...
  • 书籍介绍:本书在尊重《设计模式》原意的同时,针对JavaScript语言特性全面介绍了更适合JavaScript程序员的了16个常用的设计模式,讲解了JavaScript面向对象和函数式编程方面的基础知识,介绍了面向对象的设计原则...
  • JS设计模式

    2021-04-02 18:15:37
    策略模式 概念 将一系列相关算法封装,并使得它们可相互替换。 简单来说:通过向封装的算法传递参数,在其封装的函数中,根据参数去执行对应的函数,达到想要的目的。 可以将策略集中到一个 module 中,然后导出,...
  • SpringMVC相比Servlet到底简化了什么

    千次阅读 2020-07-24 20:43:42
    MVC不是一种设计模式,MVC是一种架构模式。当然不同的MVC存在差异。 Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不
  • 设计模式-23种设计模式

    千次阅读 2021-03-24 22:51:38
    设计模式-23种设计模式 目录 ... 装饰器6. 外观模式7. 享元模式8. 代理模式行为型1. 责任链模式2. 命令模式3. 解释器模式4. 迭代器模式5. 终结者模式6. 备忘录模式7. 观察者模式8. 状态模式9. 空对象模式10. 策略模式1
  • 设计模式简谈

    2022-02-28 16:26:01
    一、设计模式简介 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员...
  • 1、Singleton-单例模式 单例模式(Singleton Pattern)是 Java 中常见的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象...
  • 设计模式

    2021-04-22 22:49:00
    文章目录设计模式创建型模式简单工厂模式工厂方法模式抽象工厂模式建造者模式单例模式原型模式结构型模式适配器模式桥接模式组合模式装饰模式外观模式享元模式代理模式行为型模式职责链模式命令模式备忘录模式策略...
  • JavaScript设计模式

    2016-02-19 16:03:42
    Constructor(构造模式Module(模块)模式Revealing Module(揭示模块)模式Singleton(单例)模式Observer(观察者)模式Mediator(中介者)模式Prototype(原型)模式Command(命令)模式Facade(外观)模式...
  • 【设计模式

    2022-03-31 17:57:26
    【设计模式

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,008
精华内容 803
关键字:

js装饰器模式相比继承的优点