首先我们有一个抽象类(Animal
),有三个属性,和一个发声方法,如下
/// <summary>
/// 动物抽象类
/// </summary>
public abstract class Animal
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 腿的数量
/// </summary>
public int FootNum { get; set; }
/// <summary>
/// 有无尾巴
/// </summary>
public bool HaveTail { get; set; }
/// <summary>
/// 发声
/// </summary>
public abstract void Sound();
}
然后我们实现两个具体动物猫Cat
和鸭Duck
public class Cat : Animal
{
public override void Sound()
{
Console.WriteLine("喵喵喵");
}
}
public class Duck : Animal
{
public override void Sound()
{
Console.WriteLine("嘎嘎嘎");
}
}
现在我们有需求,在动物发声前,我们需要打印时间戳,而且不要修改这两个业务类。我们通过代理模式可以实现,但是通过无论是继承
还是组合
的方式,都有各自缺点。而装饰器模式
就结合它们的优点。
现在我们新建一个时间戳装饰器
类
/// <summary>
/// 时间戳装饰类
/// </summary>
public class TimeStampDecorator : Animal //这里使用继承
{
#region 这里使用组合
private readonly Animal animal = null;
/// <summary>
/// 构造方法,传入一个Animal类
/// </summary>
/// <param name="_animal"></param>
public TimeStampDecorator(Animal _animal)
{
animal = _animal;
}
#endregion
/// <summary>
/// 重写发声方法
/// </summary>
public override void Sound()
{
//在发声之前
Console.WriteLine($"时间戳:{DateTime.Now}");
//调用原来(即传入Anima)的发声方法
animal.Sound();
}
}
第一步:我们实现一个猫,然后发声
static void Main(string[] args)
{
//首先实现一个具体的猫
Animal cat = new Cat
{
FootNum = 4,
HaveTail = true,
Name = "猫"
};
//发声
cat.Sound();
Console.Read();
}
结果肯定如下
第二步:实现一个TimeStampDecorator类
新建一个TimeStampDecorator实例,构造函数需要一个Animal对象,我们把上面的cat传入
//首先实现一个具体的猫
Animal cat = new Cat
{
FootNum = 4,
HaveTail = true,
Name = "猫"
};
//新建一个TimeStampDecorator实例,构造函数需要一个Animal对象,我们把上面的cat传入
TimeStampDecorator animal = new TimeStampDecorator(cat);
第三步:用父类Animal表示animal对象
因为TimeStampDecorator
是继承自Animal
,所以我们可以用Animal
来表示animal
对象
//首先实现一个具体的猫
Animal cat = new Cat
{
FootNum = 4,
HaveTail = true,
Name = "猫"
};
//新建一个TimeStampDecorator实例,构造函数需要一个Animal对象,我们把上面的cat传入
//1. TimeStampDecorator animal = new TimeStampDecorator(cat);
Animal animal = new TimeStampDecorator(cat);
第四步:相同类用cat代替animal
上面我们对于cat
实例和animal
实例 都是Animal
类,就像我们如下定义了一样
Animal cat = new Animal();
Animal animal= new Animal();
我们知道上诉情况,我可以使用cat=animal
,所以对于第四步中,我们可以这样写
//首先实现一个具体的猫
Animal cat = new Cat
{
FootNum = 4,
HaveTail = true,
Name = "猫"
};
//新建一个TimeStampDecorator实例,构造函数需要一个Animal对象,我们把上面的cat传入
//1. TimeStampDecorator animal = new TimeStampDecorator(cat);
//2. Animal animal = new TimeStampDecorator(cat);
cat = new TimeStampDecorator(cat);
我们再让cat
发声
结果是显然的,我们在不修改Cat
类的前提下,修改了Cat
的Sound()
方法,而且这里把Cat
换成Duck
效果也是完全相同的。
当然,我们还可以套用多个装饰器,下面是一个日志装饰器
,在发声后写一个日志。
public class LogDecorator : Animal
{
private readonly Animal animal = null;
public LogDecorator(Animal _animal)
{
animal = _animal;
}
public override void Sound()
{
animal.Sound();
//发声后,我们写入日志
Console.WriteLine("成功写入了日志");
}
}
我们测试一下
static void Main(string[] args)
{
//首先实现一个具体的猫
Animal duck = new Duck
{
FootNum = 2,
HaveTail = true,
Name = "鸭子"
};
//装饰一个时间戳
duck = new TimeStampDecorator(duck);
//再装饰一个日志
duck = new LogDecorator(duck);
duck.Sound();
Console.Read();
}
结果是可预料的