装饰模式概要
顾名思义,装饰可以简单理解为旧貌新颜。即在现有基础上通过增加以达到改变。
放到开发里就是为已有的功能动态的添加更多的功能,直白一点就是
向旧有的类灵活的添加代码,以打到改变原有类的主要行为。
装饰模式的特点是新加入的东西只是为了满足一些在特定情况下才会执行的特殊行为,
把每个需要灵活使用的功能放在单独的类中,并让这个类包装他所要装饰的类,
等出现需要执行特定行为的时候,客户代码就可以在运行时根据需要灵活的有选择,有顺序的使用指定装饰类去包装对象。因为昨天的帖子有同修提出了一个关于工资的需求,所以用装饰模式按他的需求实现了一个简单的程序结构
至于实际功能肯定是没有精力去仔细分析你的工资规则而给出完整的功能性代码,毕竟我开这贴想探讨的是如果通过
前人提出的一些方法使自己的程序能拥有一个更利于维护和扩展的结构考虑到很多人看代码困难或不愿意细看,所以为了直观一点,代码的变量都用了中文,实际开发中这非常不可取,切勿模仿namespace 装饰模式
{
    class 员工
    {
        public string 员工姓名;
        public double 基本工资 = 0;
        public double 出勤 = 0;
        public double 清凉 = 0;
        public double 水电 = 0;        public 员工()
        {
        }        public 员工(string 员工姓名)
        {
            this.员工姓名 = 员工姓名;
        }        public virtual string 显示()
        {
            return 员工姓名;
        }
    }    class 工资:员工
    {
        protected 员工 员工类型变量;        public void 装饰(员工 员工类型变量)
        {
            this.员工类型变量 = 员工类型变量;
        }        public override string 显示()
        {
            if (this.员工类型变量 != null)
            {
                return this.员工类型变量.显示();
            }
            return "";
        }
    }    class 基础工资 : 工资
    {
        public override string 显示()
        {
            基本工资 = 3200;
            return base.显示()+"\n基本工资:"+基本工资;
        }
    }
            class 出勤奖:工资
    {
        public override string 显示()
        {
            出勤 = 500;
            return base.显示() + "\n出勤:" + 出勤;
        }
    }    class 清凉补贴:工资
    {
        public override string 显示()
        {
            清凉 = 400;
            return base.显示() + "\n清凉:" + 清凉;
        }
    }    class 水电扣除:工资
    {
        public override string 显示()
        {
            水电 = 300;
            return base.显示() + "\n水电:" + 水电;
        }
    }
}因为最天的帖子有人提出没有具体界面,所以增加了简单的调用namespace 装饰模式
{
    class Program
    {
        static void Main(string[] args)
        {
            员工 员工一 = new 员工("周润发");            基础工资 基础 = new 基础工资();
            出勤奖 出勤 = new 出勤奖();
            清凉补贴 清凉 = new 清凉补贴();
            水电扣除 水电 = new 水电扣除();            基础.装饰(员工一);
            出勤.装饰(基础);
            清凉.装饰(出勤);
            水电.装饰(清凉);            Console.WriteLine(水电.显示());
            Console.Read();
        }
    }
}

解决方案 »

  1.   

    本帖最后由 caozhy 于 2011-04-20 08:57:52 编辑
      

  2.   

    实际上是在写代码的时候就在考虑这个事情其实我感觉这个应该是用昨天的 策略模式 来实现比较合理这个是一个最简单的 装饰模式 实现 加以改进把工资抽象为接口的话确实从逻辑上来说是更加合理的用装饰模式来实现昨天的这个需求确实稍显牵强但若把现在的基类改为 工资 把现在的工资 改为装饰如下 从逻辑上来说就相对更合理一点
    namespace 装饰模式
    {
        class 工资
        {
            public double 基本工资 = 0;
            public double 出勤 = 0;
            public double 清凉 = 0;
            public double 水电 = 0;        public virtual string 显示()
            {
                return null;
            }
        }    class 装饰类:工资
        {
            protected 工资 工资类型变量;        public void 装饰(工资 工资类型变量)
            {
                this.工资类型变量 = 工资类型变量;
            }        public override string 显示()
            {
                if (this.工资类型变量 != null)
                {
                    return this.工资类型变量.显示();
                }
                return "";
            }
        }    class 基础工资 : 装饰类
        {
            public override string 显示()
            {
                基本工资 = 3200;
                return base.显示()+"\n基本工资:"+基本工资;
            }
        }
        class 出勤奖 : 装饰类
        {
            public override string 显示()
            {
                出勤 = 500;
                return base.显示() + "\n出勤:" + 出勤;
            }
        }    class 清凉补贴 : 装饰类
        {
            public override string 显示()
            {
                清凉 = 400;
                return base.显示() + "\n清凉:" + 清凉;
            }
        }    class 水电扣除 : 装饰类
        {
            public override string 显示()
            {
                水电 = 300;
                return base.显示() + "\n水电:" + 水电;
            }
        }
    }
      

  3.   

    考虑到功能的完整性,再次更改代码如下namespace 为了功能相对完整而添加的代码非装饰模式
    {
        class 员工
        {
            string 员工姓名 = "";
            装饰模式.工资 工资实例;        internal 装饰模式.工资 工资实例1
            {
                get { return 工资实例; }
                set { 工资实例 = value; }
            }        public 员工(string 员工姓名)
            {
                this.员工姓名 = 员工姓名;
            }        public string 领工资()
            {
                return "员工姓名:" + this.员工姓名 + "\n工资合计:" + (装饰模式.工资.基本工资
                    + 装饰模式.工资.出勤 + 装饰模式.工资.清凉 + 装饰模式.工资.水电);
            }
        }}
    namespace 装饰模式
    {
        class 工资
        {
            public static double 基本工资 = 0;
            public static double 出勤 = 0;
            public static double 清凉 = 0;
            public static double 水电 = 0;        public virtual string 显示()
            {
                return null;
            }
        }    class 装饰类:工资
        {
            protected 工资 工资类型变量;        public void 装饰(工资 工资类型变量)
            {
                this.工资类型变量 = 工资类型变量;
            }        public override string 显示()
            {
                if (this.工资类型变量 != null)
                {
                    return this.工资类型变量.显示();
                }
                return "";
            }
        }    class 基础工资 : 装饰类
        {
            public override string 显示()
            {
                工资.基本工资 = 3200;
                return base.显示()+"\n基本工资:"+基本工资;
            }
        }
        class 出勤奖 : 装饰类
        {
            public override string 显示()
            {
                工资.出勤 = 500;
                return base.显示() + "\n出勤:" + 出勤;
            }
        }    class 清凉补贴 : 装饰类
        {
            public override string 显示()
            {
                工资.清凉 = 400;
                return base.显示() + "\n清凉:" + 清凉;
            }
        }    class 水电扣除 : 装饰类
        {
            public override string 显示()
            {
                工资.水电 = 300;
                return base.显示() + "\n水电:" + 水电;
            }
        }
    }
    客户代码
    namespace 装饰模式
    {
        class Program
        {
            static void Main(string[] args)
            {
                为了功能相对完整而添加的代码非装饰模式.员工 员工一 = new 为了功能相对完整而添加的代码非装饰模式.员工("周润发");            基础工资 基础 = new 基础工资();
                出勤奖 出勤 = new 出勤奖();
                清凉补贴 清凉 = new 清凉补贴();
                水电扣除 水电 = new 水电扣除();            基础.装饰(员工一.工资实例1);
                出勤.装饰(基础);
                清凉.装饰(出勤);
                水电.装饰(清凉);            员工一.工资实例1 = 水电;            Console.WriteLine("工资明细:" + 水电.显示() + "\n" + 员工一.领工资());
                Console.Read();
            }
        }
    }运行结果
      

  4.   


    回 13 楼的朋友问题一 是什么
    这个问题相信随便百度或翻书都能得到比我回答更华丽更准确的答案
    就我粗浅的理解 面相对象 就是把一些相关的东西抽象为一个对象,反应到代码中即 把一组相关的功能封装为一个类。
    如 把 人 看做一个对象 (反应到代码则把 人 定义为一个类)
    身高,体重 则是 人 这个对象拥有的属性 (反应到代码中即为 类 字段)
    吃喝拉撒 则是 人 这个对象拥有的一些功能(反应到到代码中既为 类 的方法)问题二 能做什么
    这个我实在没理解你问题的意思,按字面理解答 面相过程编程 能做的 面相对象都能做问题三 如何使用
    其实现在的语言不管你怎么用,语言本身就已经限定了你只能面相对象,c#的方法就没办法定义到类外面不是吗?你的问题真的很难理解回答
    如何使用?从具体中抽象出解决问题的过程并按过程之间逻辑关系组织成类?问题四 好处
    这个真的太多,你的问题都太泛太大,就相较面相过程的编程方式而言最明显的好处是通过封装、多态、继承避免数据和过程分离引出的弊端,使代码更易扩展和复用,极大的提升了代码的可维护性。问题五 是不是一定要使用他
    不管面相过程还是面向对象都只是方法,而方法的目的是为了满足需求,那既然有更好的方法能满足需求何乐而不为呢?就好比我要从地点a到地点b,我的目的是到达地点b,而到达的方法可以有很多,走着去,骑自行车,汽车,飞机,轮船?有了交通工具我干嘛要走路去?这个比喻不太恰当,个人水平有限,本着尽力回答每位朋友的问题,希望我的答案能对你有所帮助
      

  5.   

    本帖最后由 caozhy 于 2011-04-20 08:51:38 编辑
      

  6.   

    本帖最后由 caozhy 于 2011-04-20 10:09:47 编辑
      

  7.   

    嘿~有收获,原来只懂得Observer和单例…囧
      

  8.   

    本帖最后由 caozhy 于 2011-04-20 09:57:23 编辑
      

  9.   

    当看到  class 工资:员工 这里时感觉怪怪的。工资和员工会有这种关系?装饰者模式 A a =new A();
    A1 a1=new A1(a); -- 装饰
    A2 a2=new A2(a1); -- 再装饰。
    a1,a2中的某个属性,通过继承中构造函数关系来处理。如工资, a是普通员工 的工次在 A() {this.payment=3000.00;}
    a1是组长  A1() {base.Payment+1000.00;};
    a2是经理  A2() {base.Payment+提成+业绩*10+}
    这类的。
      

  10.   

    本帖最后由 caozhy 于 2011-04-20 11:45:15 编辑
      

  11.   

    楼主,需要跟你说一下,那个工资的例子是我跟你提的,我说一下我的意图,就是系统要做的足够灵活,能适应各种业务的变化,设计模式就是用来解决这种复杂多变的业务的。这个变化有横向变化,和纵向变化。先说 “横向变化”,
    比如 工资项目的可变,
    比如你定义的项目是下面这些:
            public double 基本工资 = 0;
            public double 出勤 = 0;
            public double 清凉 = 0;
            public double 水电 = 0;但后来 客户又要 增加一个 “扣押金”的项目,你怎么加?
    你不可能又要去改程序,在程序里增加一个“扣押金”的属性吧,
    所以你没有使用 设计模式来解决这个 横向变化。
      

  12.   

    本帖最后由 caozhy 于 2011-04-20 12:37:27 编辑
      

  13.   

    我发那时候我设计的表结构给你:http://blog.csdn.net/weishaolin131083/archive/2011/04/19/6333369.aspx还有界面:http://blog.csdn.net/weishaolin131083/archive/2011/04/19/6333483.aspx
      

  14.   

    本帖最后由 caozhy 于 2011-04-20 14:41:10 编辑
      

  15.   

    本帖最后由 caozhy 于 2011-04-20 14:06:28 编辑
      

  16.   

    本帖最后由 caozhy 于 2011-04-20 14:34:32 编辑
      

  17.   

    重构下代码,使得调用看起来更顺畅:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;namespace ConsoleApplication1
    {
        class Program
        {
            //客户端
            static void Main(string[] args)
            {
                Employee e = new Employee("周润发");
                Employee e1 = new Employee("刘德华");            e.GetSalary().加上("基本工资", 6000).
                    加上("出勤奖", 300).
                    加上("清凉补贴", 200).
                    在总数的基础上加上("董事长奖金 15%", (x => x * 0.15)).
                    加上("新年/平时补贴", () =>
                        {
                            if (DateTime.Now.Month == 1) 
                                return 1000.0; 
                            else
                                return 500.0;
                        }).
                    扣除("水电扣除", 100);            e1.GetSalary().加上("基本工资", 4000).
                    加上("出勤奖", 300).
                    在总数的基础上加上("董事长奖金 25%", (x => x * 0.25)).
                    加上("岗位津贴", 2000).
                    加上("清凉补贴", 200).
                    扣除("水电扣除", 120);            e.DisplaySalary();
                e1.DisplaySalary();
            }
        }    //定义一个员工类,注意,这里一点工资的概念没有出现
        class Employee
        {
            public string Name { get; set; }
            public Employee(string name) { Name = name; }
            public override string ToString()
            {
                return Name;
            }
        }    static class EmployeeSalaryHelper
        {
            private class SalaryItem
            {
                public bool Add {get; private set; }
                public Func<double, double> Calc { get; private set; }
                public string Description { get; private set; }
                public bool AfterCount { get; private set; }
                public SalaryItem(bool add, double calc, string description)
                {
                    Description = description;
                    Calc = (x) => calc;
                    Add = add;
                    AfterCount = false;
                }
                public SalaryItem(bool add, Func<double, double> calc, string description)
                {
                    Description = description;
                    Calc = calc;
                    Add = add;
                    AfterCount = true;
                }
            }        //为每个Employee提供一个Salary对象
            public class EmployeeSalary
            {
                private List<SalaryItem> Salaries { get; set; }            public EmployeeSalary() { ResetEmployeeSalary(); }            public void ResetEmployeeSalary() { Salaries = new List<SalaryItem>(); }            public EmployeeSalary 加上(string description, double calc)
                { 
                    Salaries.Add(new SalaryItem(true, calc, description));
                    return this;
                }
                public EmployeeSalary 加上(string description, Func<double> calc)
                {
                    Salaries.Add(new SalaryItem(true, (x) => calc(), description));
                    return this;
                }
                public EmployeeSalary 在总数的基础上加上(string description, Func<double, double> calc)
                {
                    Salaries.Add(new SalaryItem(true, calc, description));
                    return this;
                }
                public EmployeeSalary 扣除(string description, double calc)
                {
                    Salaries.Add(new SalaryItem(false, calc, description));
                    return this;
                }
                public EmployeeSalary 扣除(string description, Func<double> calc)
                {
                    Salaries.Add(new SalaryItem(false, (x) => calc(), description));
                    return this;
                }
                public EmployeeSalary 在总数的基础上扣除(string description, Func<double, double> calc)
                {
                    Salaries.Add(new SalaryItem(false, calc, description));
                    return this;
                }            public double Count
                {
                    get 
                    {
                        var items = (from s in Salaries where s.AfterCount == false select s).ToList();
                        double result = 0;
                        items.ForEach(item => result += (item.Add ? 1: -1) * item.Calc(0));
                        return result;
                    }
                }
                public double Value
                {
                    get
                    {
                        double count = Count;
                        var items = (from s in Salaries where s.AfterCount == true select s).ToList();
                        double result = count;
                        items.ForEach(item => result += (item.Add ? 1: -1) * item.Calc(count));
                        return result;
                    }
                }            public override string ToString()
                {
                    double count = Count;
                    StringBuilder sb = new StringBuilder("工资明细:\n");
                    var items1 = (from s in Salaries where s.AfterCount == false select s).ToList();
                    items1.ForEach(item => sb.AppendLine("\t" + item.Description + ":\t" + Convert.ToString ((item.Add ? 1 : -1) * item.Calc(count))));
                    sb.AppendLine("\t小计:\t" + Convert.ToString(count));
                    var items2 = (from s in Salaries where s.AfterCount == true select s).ToList();
                    items2.ForEach(item => sb.AppendLine("\t" + item.Description + ":\t" + Convert.ToString((item.Add ? 1 : -1) * item.Calc(count))));
                    sb.AppendLine("\t实发:\t" + Convert.ToString(Value));
                    return sb.ToString();
                }
            }        //存储所有的员工工资信息
            private static Dictionary<Employee, EmployeeSalary> _data { get; set; }        //类静态构造函数
            static EmployeeSalaryHelper() { _data = new Dictionary<Employee, EmployeeSalary>(); }        //获取工资
            public static EmployeeSalary GetSalary(this Employee employee)
            {
                if (employee == null) throw new NullReferenceException();
                if (!_data.ContainsKey(employee)) _data.Add(employee, new EmployeeSalary());
                return _data[employee];
            }        //输出
            public static void DisplaySalary(this Employee employee)
            {
                //这里无需再次判断this是否为null
                Console.WriteLine(String.Format("{0}\n{1}", employee.Name, _data[employee]));
            }
        }
    }