zoukankan      html  css  js  c++  java
  • C#设计模式:装饰者模式(Decorator Pattern)

    一,装饰者模式(Decorator Pattern):装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。

    二,在以上代码中我们是中国人是根本行为,我们给中国人装饰我会说英语,我会说日语和我会说英语我会说日语这三种行为,那按正常的理解来说,这是多态,那我们对People中的Say我们是不是需要有三种实现方法呢?三种还是比较好解决,但是如果我们有N种呢?难道我们要有N个实现类么?这时我们就可以使用装饰者模式。

    1》我们抽象People这个类,还有抽象的Say方法方法,这时People就可以有多国人的实现,我们使用一种中国人,假设,这是我们现有的代码的,但根据需求,我们需要给中国人添加我会说英语,我会说日语和我会说英语我会说日语这三种行为,那该怎么办?根据以往想法,一般如下设计:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Demo
    {
        class Program
        {
            static void Main(string[] args)
            {
                People p = new Englist();
                p.Say();
                People p1 = new Jan();
                p1.Say();
                People p2 = new JE();
                p2.Say();
            }
        }
        public abstract class People 
        {
            public abstract void Say();
        }
        public class Chinese : People
        {
            public override void Say()
            {
                Console.WriteLine("我是中国人");
            }
        }
        public class Englist : Chinese
        {
            public override void Say()
            {
                base.Say();
                Console.WriteLine("我是会说英语");
            }
        }
        public class Jan : Chinese
        {
            public override void Say()
            {
                base.Say();
                Console.WriteLine("我是会说日语");
            }
        }
        public class JE : Chinese
        {
            public override void Say()
            {
                base.Say();
                Console.WriteLine("我是会说英语和日语");
            }
        }
    }

    2》然而我们如果还有N种装饰中国人,难道要写N个子类?但是明显是不合理的,这时我们该怎么对chinese扩展呢?我们使用装饰者模式看看,如下代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _8.装饰者模式
    {
        //装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。
        class Program
        {
            static void Main(string[] args)
            {
                People p = new Chinese();            //没有扩展的实现
    
                Decorator d = new Englist(p);        //将会说英语的扩展给中国人
                d.Say();
                Console.WriteLine("----------------------
    ");
    
                Decorator d1 = new Jan(p);            //将会说日语的扩展给中国人
                d1.Say();
                Console.WriteLine("----------------------
    ");
    
                Englist e = new Englist(p);     //将会说英语和日语的扩展给中国人,这里是装饰者模式的核心,当我们存在这里三种可能的组合时,正常逻辑可能是每一种都实现一次,这样就存在三个实现子类,但是如果可能组合有几十上百种怎么办,这时我们可以使用装饰者模式,在代码中,我们只是实现说英语和说日语的两种可能,但我们可以实现组合得出第三种可能,这样代码就可以减少很多。
                Jan j = new Jan(e);
                j.Say();
            }
        }
    
        public abstract class People
        {
            public abstract void Say();
        }
        public class Chinese : People
        {
            public override void Say()         //根本的行为
            {
                Console.Write("我是中国人");
            }
        }
    
        public abstract class Decorator : People
        {
            public People people;
            public Decorator(People p)
            {
                this.people = p;
            }
    
            public override void Say()
            {
                people.Say();
            }
        }
        public class Englist : Decorator
        {
            public Englist(People p)
                : base(p)
            {
            }
    
            public override void Say()
            {
                base.Say();
    
                // 添加新的行为,动态地扩展一个对象的功能
                SayEnglish();
            }
    
            /// <summary>
            /// 新的行为方法
            /// </summary>
            public void SayEnglish()
            {
                Console.WriteLine("我会说英语");
            }
        }
    
        public class Jan : Decorator
        {
            public Jan(People p)
                : base(p)
            {
            }
    
            public override void Say()
            {
                base.Say();
    
                // 添加新的行为,动态地扩展一个对象的功能
                SayJan();
            }
    
            /// <summary>
            /// 新的行为方法
            /// </summary>
            public void SayJan()
            {
                Console.WriteLine("我会说日语");
            }
        }
    }

     两个代码对比,我们是不是发现少了一个子类的实现?,这样也减少了代码量。

    3》但为什么下面代码可以实现两种组合?我们来理清点思路

    Englist e = new Englist(p);     
    Jan j = new Jan(e);
    j.Say();

    在上文中,我们的Englist 是继承Decorator而构造变量是People类型,但我们实例Englist 时,我们也传入了一个抽象people接收Chinese创建的中国人实例的变量进来,然后传给Englist ,而此时,人的对象已经传给Englist ,而Englist继承decorator,同时decorator继承people,我们重写Say()并调用的中国人的实现的方法Say()和调用SayEnglist(),这样我们就可以给原本的中国人装饰上说英语这一行为,如下代码:

         public override void Say()
            {
                base.Say();
    
                // 添加新的行为,动态地扩展一个对象的功能
                SayEnglist();
            }

     4》那我们要同时说英语的日语呢?

    根据3》中我么可以知道3中的Say方法代码已经综合了说英文,我们的思路是不是可以说,重写英语的Say(),调用英语的Say()和调用说日语的方法SayJan()就可以了?而不是说实现多一个子类。那为什么下面这句代码可以实现呢?综合了两种说话的行为呢?

    Jan j = new Jan(e);

    我们来理解下,在上文我们实例的英语已经重写了Say的方法,而此时的Say()是已经包含了说英语的功能,同时Englist继承的父类最根本的就是people,根据继承的原则,我们是不是可以将Englist对象传给people,这里我们在看看Jan内重写Say()方法,并调用说日语的方法,这时不就可以同时给中国人添加两种行为了么

    5》相对于同一个具体物件装饰器

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace _08.装饰者模式
    {
        /// <summary>
        /// 装饰者模式属于结构型模式,装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。
        /// 装饰者模式通过创建一个包装对象(wrapper),也就是用装饰来包裹真实的对象。
        /// </summary>
        class Program
        {
            static void Main(string[] args)
            {
                People p = new China();
                p = new PeopleDecorator(p);
                p = new Chinese(p);
                p = new Englist(p);
                p.DoSome();
            }
        }
        /// <summary>
        /// People充当抽象构件。
        /// </summary>
        public abstract class People
        {
            public abstract void DoSome();
        }
        /// <summary>
        /// China充当具体构件
        /// </summary>
        public class China: People
        {
            public override void DoSome()
            {
                Console.WriteLine("我是中国人!!!");
            }
        }
        /// <summary>
        /// 抽象装饰(Decorator)
        /// </summary>
        public class PeopleDecorator : People
        {
            private People _people = null;
            public PeopleDecorator(People people)
            {
                this._people = people;
            }
            public override void DoSome()
            {
                _people.DoSome();
            }
        }
        /// <summary>
        /// 具体装饰(Concrete Decorator)
        /// </summary>
        public class Chinese : PeopleDecorator
        {
            private People _people = null;
            public Chinese(People people) : base(people)
            {
                this._people = people;
            }
            public override void DoSome()
            {
                _people.DoSome();
                Console.WriteLine("我说中文");
            }
        }
        /// <summary>
        /// 具体装饰(Concrete Decorator)
        /// </summary>
        public class Englist : Chinese
        {
            private People _people = null;
            public Englist(People people) : base(people)
            {
                this._people = people;
            }
            public override void DoSome()
            {
                _people.DoSome();
                Console.WriteLine("我说英语");
            }
        }
    }
  • 相关阅读:
    SpringBoot自动装配源码
    对称加密、非对称加密、数字签名
    k8s部署mysql数据持久化
    docker部署 springboot 多模块项目+vue
    ES入门及安装软件
    prometheus入门介绍及相关组件、原理讲解
    流水线 Sonar 代码扫描
    postgresql数据库 查询表名、备注及字段、长度、是否可控、是否主键等信息
    Helm中Tiller镜像下载失败的解决办法
    程序员孔乙己
  • 原文地址:https://www.cnblogs.com/May-day/p/8574842.html
Copyright © 2011-2022 走看看