深入理解Java设计模式之装饰模式

目录
  • 一、前言
  • 二、什么是装饰模式
    • 1.定义:
    • 2.意图
    • 3.别名
    • 4.动机
    • 5.作用
    • 6.问题
  • 三、装饰模式的结构
  • 四、装饰模式的使用场景
  • 五、装饰模式的优缺点
  • 六、装饰模式的实现
  • 七、装饰模式的.NET应用
  • 八、总结

一、前言

装饰模式实际上是一直提倡的组合代替继承的实践方式,个人认为要理解装饰者模式首先需要理解为什么需要组合代替继承,继承又是为什么让人深恶痛绝.

为什么建议使用组合代替继承?

面向对象的特性有继承与封装,但两者却又有一点矛盾,继承意味子类依赖了父类中的实现,一旦父类中改变实现则会对子类造成影响,这是打破了封装性的一种表现. 而组合就是巧用封装性来实现继承功能的代码复用.

二、什么是装饰模式

1.定义:

装饰器模式又名包装(Wrapper)模式。装饰器模式以对客户端透明的方式拓展对象的功能,是继承关系的一种替代方案。

2.意图

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

3.别名

包装器Wrapper

4.动机

有时我们希望给某个对象而不是整个类添加一些功能。例如,一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些组件,例如边框,或是一些行为,例如窗口滚动等。

5.作用

在不修改原有的接口的情况下,让类表现的更好。

6.问题

自然是继承有一些问题

继承会导致超类和子类之间存在强耦合性,当超类改变时,子类也会随之改变;

超类的内部细节对于子类是可见的,继承常常被认为破坏了封装性;

三、装饰模式的结构

在装饰器模式中的角色有:

  • 抽象构件(Component)角色:给出一个抽象接口,已规范准备接收附加责任的对象。
  • 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类
  • 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。

四、装饰模式的使用场景

1.需要扩展一个类的功能或给一个类增加附加责任。

2.需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

3.需要增加由一些基本功能的排列组合而产生的非常大量的功能

五、装饰模式的优缺点

优点:

1.装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活

2.通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合

3.装饰者模式有很好地可扩展性

缺点:

装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

六、装饰模式的实现

/// <summary>
    /// 手机抽象类,即装饰者模式中的抽象组件类
    /// </summary>
    public abstract class Phone
    {
        public abstract void Print();
    }
     /// <summary>
    /// 苹果手机,即装饰着模式中的具体组件类
    /// </summary>
    public class ApplePhone:Phone
    {
        /// <summary>
        /// 重写基类方法
        /// </summary>
        public override void Print()
        {
            Console.WriteLine("开始执行具体的对象——苹果手机");
        }
    }
     /// <summary>
    /// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Photo
    /// </summary>
    public abstract class Decorator:Phone
    {
        private Phone phone;
         public Decorator(Phone p)
        {
            this.phone = p;
        }
         public override void Print()
        {
            if (phone != null)
            {
                phone.Print();
            }
        }
    }
     /// <summary>
    /// 贴膜,即具体装饰者
    /// </summary>
    public class Sticker : Decorator
    {
        public Sticker(Phone p)
            : base(p)
        {
        }
         public override void Print()
        {
            base.Print();
             // 添加新的行为
            AddSticker();
        }
         /// <summary>
        /// 新的行为方法
        /// </summary>
        public void AddSticker()
        {
            Console.WriteLine("现在苹果手机有贴膜了");
        }
    }
     /// <summary>
    /// 手机挂件
    /// </summary>
    public class Accessories : Decorator
    {
        public Accessories(Phone p)
            : base(p)
        {
        }
         public override void Print()
        {
            base.Print();
             // 添加新的行为
            AddAccessories();
        }
         /// <summary>
        /// 新的行为方法
        /// </summary>
        public void AddAccessories()
        {
            Console.WriteLine("现在苹果手机有漂亮的挂件了");
        }
    }

客户端代码

class Customer
    {
        static void Main(string[] args)
        {
            // 我买了个苹果手机
            Phone phone = new ApplePhone();
             // 现在想贴膜了
            Decorator applePhoneWithSticker = new Sticker(phone);
            // 扩展贴膜行为
            applePhoneWithSticker.Print();
            Console.WriteLine("----------------------\n");
             // 现在我想有挂件了
            Decorator applePhoneWithAccessories = new Accessories(phone);
            // 扩展手机挂件行为
            applePhoneWithAccessories.Print();
            Console.WriteLine("----------------------\n");
             // 现在我同时有贴膜和手机挂件了
            Sticker sticker = new Sticker(phone);
            Accessories applePhoneWithAccessoriesAndSticker = new Accessories(sticker);
            applePhoneWithAccessoriesAndSticker.Print();
            Console.ReadLine();
        }

从上面的客户端代码可以看出,客户端可以动态地将手机配件增加到手机上,如果需要添加手机外壳时,此时只需要添加一个继承Decorator的手机外壳类,从而,装饰模式扩展性也非常好。

七、装饰模式的.NET应用

在.NET 类库中也有装饰者模式的实现,该类就是System.IO.Stream

MemoryStream memoryStream = new MemoryStream(new byte[] {95,96,97,98,99});
             // 扩展缓冲的功能
            BufferedStream buffStream = new BufferedStream(memoryStream);
             // 添加加密的功能
            CryptoStream cryptoStream = new CryptoStream(memoryStream,new AesManaged().CreateEncryptor(),CryptoStreamMode.Write);
            // 添加压缩功能
            GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true);

八、总结

装饰者模式本质上来说是AOP思想的一种实现方式,其持有被装饰者,因此可以控制被装饰者的行为从而达到了AOP的效果。

要点:

1:继承属于扩展形式一种,但不见的是达到弹性设计的最佳方式,组合优于继承。

2:应该允许行为可以被拓展,而无需修改现有的代码。

3:装饰者模式意味着一群装饰者类,这些类用来包装具体组件。

4:装饰者类反映出被装饰组件类型。

5:可以使用无数个装饰者包装一个组件。

6:装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java设计模式之代理模式与装饰模式实例详解

    本文实例讲述了Java设计模式之代理模式与装饰模式.分享给大家供大家参考,具体如下: 之所以把这两种模式放在一起说,是因为我发现这了两种模式几乎一模一样! 从网上也搜了一些资料,发现两者还是有一些区别的.我们在学习的同时也把这种困惑搞清楚. 定义: 代理模式,为其他对象提供一种代理以控制对这个对象的访问. 装饰模式,动态地给一个对象添加一些额外的职责. 代理模式,很好理解,就是把一个对象再次封装,以后就对封装的对象访问就可以了. 因为代理对象已经取代了被代理对象. 装饰模式,给一个对象增加功能,

  • Java设计模式之装饰模式原理与用法实例详解

    本文实例讲述了Java设计模式之装饰模式原理与用法.分享给大家供大家参考,具体如下: 装饰模式能在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象.JDK中IO的设计就用到了装饰模式,通过过滤流对节点流进行包装来实现功能的扩展. 装饰模式的角色的组成: ① 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加工功能的对象.(InputStream.OutputStream) ② 具体构件(Concrete Co

  • Java设计模式之装饰模式详解

    一.装饰模式引入例子 一个快餐店计算价格问题举例: 快餐店有炒面.炒饭这些快餐,可以额外附加鸡蛋.火腿.培根这些配菜,加配菜需要额外加钱,并且每个配菜的价钱不一样,计算快餐价格如何实现? 1.1 一般设计 1.2 使用继承方式的一般设计存在的问题 横向扩展性不好:如果要再加一种配料(火腿肠),我们就会发现需要给FriedRice和FriedNoodles分别定义一个子类.如果要新增一个快餐品类(炒河粉)的话,就需要定义更多的子,会出现类爆炸的问题. 继承适合于纵向扩展 二.装饰模式 2.1 装饰

  • java设计模式学习之装饰模式

    装饰模式:动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活. 优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能. 缺点:多层装饰比较复杂. 实例:给一个人配置穿衣 1:代码结构图 2:创建一个person类(  ConcreteComponent) package DecoratorModel; /** * 2017-10-9 10:39:09 * 装饰器设计模式 * Person 类 Concre

  • Java通俗易懂系列设计模式之装饰模式

    介绍 装饰模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式.就功能而言,装饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能. 意图:动态地给一个对象添加一些额外的职责和增加功能. 主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀. 何时使用:在不想增加很多子类的情况下扩展类. 如何解决:将具体功能职责划分,同时继承装饰者模式. 关键代码: 1.Component 类充当抽象角色,不

  • java设计模式笔记之装饰模式

    一.装饰模式的定义 装饰模式是一种比较常见的模式,其定义如下:Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.(动态地给一个对象添加额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活) 装饰模式的通

  • 深入理解Java设计模式之装饰模式

    目录 一.前言 二.什么是装饰模式 1.定义: 2.意图 3.别名 4.动机 5.作用 6.问题 三.装饰模式的结构 四.装饰模式的使用场景 五.装饰模式的优缺点 六.装饰模式的实现 七.装饰模式的.NET应用 八.总结 一.前言 装饰模式实际上是一直提倡的组合代替继承的实践方式,个人认为要理解装饰者模式首先需要理解为什么需要组合代替继承,继承又是为什么让人深恶痛绝. 为什么建议使用组合代替继承? 面向对象的特性有继承与封装,但两者却又有一点矛盾,继承意味子类依赖了父类中的实现,一旦父类中改变实

  • 快速理解Java设计模式中的组合模式

    组合模式是一种常见的设计模式(但我感觉有点复杂)也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系. 个人理解:组合模式就是将部分组装成整体. 定义如下: 将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 通用类图如下: 组合模式的包含角色: ● Component 抽象构件角色 定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性. ● Leaf 叶子构件 叶子对象,其下再也没有其他的分支,也就是遍历的最

  • Java设计模式之装饰模式(Decorator模式)介绍

    Decorator常被翻译成"装饰",我觉得翻译成"油漆工"更形象点,油漆工(decorator)是用来刷油漆的,那么被刷油漆的对象我们称decoratee.这两种实体在Decorator模式中是必须的. Decorator定义:动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活. 为什么使用Decorator 我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生

  • 深入理解Java设计模式之策略模式

    目录 一.什么是策略模式 二.策略模式的结构 三.策略模式的应用场景 四.策略模式的优缺点 六.策略模式的实现 七.策略模式和简单工厂模式的结合 八.策略枚举的实现 九.总结 一.什么是策略模式 策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户.需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数. 策略模式定义和封装了一系列的算法,它们是可以相互替换的,也就是说它们具有

  • 深入理解Java设计模式之桥接模式

    目录 二.桥接模式的结构 三.桥接模式的使用场景 四.桥接模式的优缺点 五.装饰,桥接和适配器模式的异同 适配器模式: 桥接模式: 装饰器模式: 六.桥接模式的实现 七.总结 一.什么是桥接模式 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化.它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式. 二.桥接模式的结构 在桥接模式结构图中包含如下几个角色: Abstraction(抽象类):用于定义

  • java设计模式之装饰模式详细介绍

    1.    装饰模式(Decorator)的定义:又名包装(Wrapper)模式,装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 2.    装饰模式以对客户端透明的方式动态的给一个对象附加上更多的责任.换言之客户端并不会觉的对象在装饰前和装饰后有什么区别. 3.    装饰模式可以在不创造更多的子类的模式下,将对象的功能加以扩展. 4.    装饰模式与类继承的区别: 1)    装饰模式是一种动态行为,对已经存在类进行随意组合,而类的继承是一种静态的行为,一个类定义成

  • 理解Java设计模式编程中的迪米特原则

    定义:一个对象应该对其他对象保持最少的了解. 问题由来:类与类之间的关系越密切,耦合度越大,当一个类发生改变时,对另一个类的影响也越大. 解决方案:尽量降低类与类之间的耦合.          自从我们接触编程开始,就知道了软件编程的总的原则:低耦合,高内聚.无论是面向过程编程还是面向对象编程,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率.低耦合的优点不言而喻,但是怎么样编程才能做到低耦合呢?那正是迪米特法则要去完成的.          迪米特法则又叫最少知道原则,最早是在1987年

  • 理解java设计模式之建造者模式

    建造者模式(Builder Pattern)主要用于"分步骤构建一个复杂的对象",在这其中"分步骤"是一个稳定的算法,而复杂对象的各个部分则经常变化.因此, 建造者模式主要用来解决"对象部分"的需求变化. 这样可以对对象构造的过程进行更加精细的控制. package com.shejimoshi.create.Builder; /** * 功能:意图是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 * 适用性: * 当创

随机推荐