zl程序教程

您现在的位置是:首页 >  后端

当前栏目

C# 设计模式(9)装饰者

2023-09-14 09:16:28 时间

参考:head first 设计模式
参考:https://www.cnblogs.com/zhili/p/DecoratorPattern.html

装饰者与桥接区别

桥接模式:必须由一方使用抽象类,持有使用接口的一方
装饰者模式:装饰者模式是实现接口,桥接模式是以组合的方式持有接口

应用场景

开发中我们经常想要对一类对象添加不同的功能。例如要给手机添加贴膜,挂件,外壳等
/如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone贴膜是手机类,
AccessoriesPhone挂件类等,这样会导致子类爆炸,解决这个问题我们可以用装饰者模式来动态地给一个对象添加额外的职责,装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类,可以更加灵活地增加功能

1.需要扩展一个类的功能或者给一个类增加附加责任
2.需要动态的给一个对象增加功能,这些功能可以动态的撤销
3.需要增加由一些基本功能的排列组合而产生非常大量的功能

结构

装饰者模式采对象组合而非继承的方式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”,同时它能很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。

抽象构件:Phone角色:给出一个抽象接口以规范准备接受附加责任的对象
具体构件:ApplePhone角色:定义一个将要接受附加责任的类
装饰角色:Decorator角色:持有一个构件Component对象的实例,并定义一个与抽象构件接口一致的接口
具体装饰:Sticke和Accessories角色:负责给构件对象“贴上”附加的责任

图例

在这里插入图片描述在这里插入图片描述

特点

优点:
装饰者模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更加灵活,通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合,扩展性要好些。
缺点:
导致设计中出现小对象,过度使用会让程序复杂。并且更多的对象导致查错困难。

系统自带

.net自带的System.IO.Stream
Stream>GzipStream,CryptoStream,BufferedStream,FileStream,MemoryStream,NetWorkStream
BufferedStream,CryptoStream,GZIpStream其实就是两个具体装饰类,这里的装饰者模式省掉了抽象装饰器角色(Decorator)。
System.IO.MemoryStream ms = new System.IO.MemoryStream(new byte[] { 1, 2, 3 }) ;
System.IO.BufferedStream bs = new System.IO.BufferedStream(ms);
System.IO.Compression.GZipStream gs = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Compress, true);

代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DesignPattern
{
    public class DecoratorPattern
    { 
        public static void main()
        {
            //买个新手机
            Phone p = new ApplePhone();
            //想贴膜了
            Decorator d = new Sticker(p);
            d.Print();

            //想要挂件了
            Decorator dd = new Accessories(p);
            dd.Print();

            //现在我同事有贴膜和挂件了 
            Sticker sticker = new Sticker(p);
            Accessories a = new Accessories(sticker);
            a.Print();

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


        /// <summary>
        /// 手机抽象类,即装饰者模式中的抽象组件类
        /// </summary>
        public abstract class Phone
        {
            public abstract void Print();
        }

        /// <summary>
        /// 苹果手机 即装饰者模式中的具体组件类
        /// </summary>
        public class ApplePhone : Phone
        {
            public override void Print()
            {
                Console.WriteLine("开始 苹果手机");
            }
        }

        /// <summary>
        /// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Phone
        /// </summary>
        public abstract class Decorator : Phone
        {
            private Phone phone;

            public Decorator(Phone p)
            {
                this.phone = p;
            }

            public override void Print()
            {
                phone?.Print();
            }
        }

        /// <summary>
        /// 贴膜 即具体装饰者
        /// </summary>
        public class Sticker : Decorator
        {
            public Sticker(Phone p)
                : base(p)
            {

            }

            public override void Print()
            {
                base.Print();
                //添加新的行为
                AddSticker();
            }

            public void AddSticker()
            {
                Console.WriteLine("现在手机有贴膜了");
            }
        }

        /// <summary>
        /// 挂件 具体装饰者
        /// </summary>
        public class Accessories : Decorator
        {
            public Accessories(Phone p) : base(p) { }

            public override void Print()
            {
                base.Print();
                AddAccessories();
            }

            public void AddAccessories()
            {
                Console.WriteLine("现在手机有挂件了");
            }
        }
    }
}