装饰模式

 

 

一、完成者信息:

姓名:张璐璐

学号:07770232

 

二、模式信息

模式名称:装饰模式

 

生活场景:加工蛋糕的场景:现有烤好的蛋糕,接下来我们要给蛋糕切好形状,然后涂上奶油或巧克力,再放上草莓,最后插上蜡烛。

1.不假思索的思路:

按类继承的作法如下:

类图:

 

代码
public abstract class Cake //抽象蛋糕
{
public abstract void Shape();
public abstract void Flavor();
}
各种蛋糕

public class Cream:Cake//奶油蛋糕
{
public override void Shape()
{
Console.WriteLine(
"把蛋糕切成三角形");
}

public override void Flavor()
{
Console .WriteLine (
"涂上奶油");
}
}

public class Chocolate:Cake //巧克力蛋糕
{
public override void Shape()
{
Console .WriteLine (
"把蛋糕切成正方形");
}

public override void Flavor()
{
Console .WriteLine (
"涂上巧克力");
}
}

各种不同装饰的组合:如:caomei有加上草莓的接口、lazhu是插上蜡烛的接口、dianran是燃蜡的接口。
public interface caomei
{
public void Strawberry()
{
Console.WriteLine(
"放上草莓");
}
}


public interface lazhu
{
public void candle()
{
Console.WriteLine(
"插上蜡烛");
}

}

public interface dianran
{

public void Light()
{
Console.WriteLine(
"点燃蜡烛");
}
}

各种排列组合
public class CreamA:Cream ,caomei
{
//放上草莓
}
public class CreamB:Cream ,lazhu
{
//插上蜡烛
}
public class CreamC:Cream ,dianran
{
//点燃蜡烛
}

public class ChocolateA:Chocolate ,caomei
{
//加草莓
}
public class ChocolateB:Chocolate ,lazhu
{
//插上蜡烛
}
public class ChocolateC:Chocolate ,dianran
{
//点燃蜡烛
}

 

存在问题:

由此可见,如果用类继承实现,子类会爆炸式地增长。
动机(Motivate):
 上述描述的问题根源在于我们“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态物质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能组合)会导致更多子类的膨胀(多继承)。

 

2.归纳阶段

如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?
意图(Intent):
  动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
                                                             ------《设计模式》GOF

 

用装饰模式修改后的类图

 

代码
namespace Decorator1
{
public abstract class Cake //定义抽象类 (普通的蛋糕,上面什么也没有)
{
public abstract void Shape();//形状
public abstract void Flavor();//味道
}
}
public class Cream:Cake //定义具体类--奶油蛋糕
{
public override void Shape()
{
Console.WriteLine(
"把蛋糕切成三角形,");
}

public override void Flavor()
{
Console.WriteLine(
"涂上奶油");
}
}
public class Chocolate:Cake //定义具体蛋糕--巧克力蛋糕
{
public override void Shape()
{
Console.WriteLine(
"把蛋糕切成方形,");
}

public override void Flavor()
{
Console.WriteLine(
"涂上巧克力,");
}
}
public abstract class decorator : Cake //定义抽象装饰类,定义一个与抽象构件接口(cake)一致的接口。
{
private Cake cake;

public decorator(Cake cake)
{
this.cake = cake;
}

public override void Shape()
{
cake .Shape ();
}

public override void Flavor()
{
cake .Flavor ();
}
}
public class decoratorA:decorator //定义具体装饰类A
{
public decoratorA(Cake cake) //调用父类的构造函数
: base(cake)
{

}

private string addedState;

public override void Shape()
{
base.Shape();
}

public override void Flavor()
{
base.Flavor();

addedState
= "放上草莓";
Console.WriteLine(addedState );
}
}
public class decoratorB : decorator //定义具体装饰类B
{
public decoratorB(Cake cake)//调用父类的构造函数
: base(cake)
{ }

private string addedState;

public override void Shape()
{
base.Shape();
}

public override void Flavor()
{
base.Flavor();

addedState
= "再插上蜡烛。";
Console.WriteLine(addedState);
}
}
class Program
{
static void Main(string[] args)
{

Cake cake
= new Cream();

decoratorA da
= new decoratorA(cake ); //且有草莓的
decoratorB db = new decoratorB(da); //且有草莓和蜡烛的
Console.WriteLine("==========奶油蛋糕===========");
db.Shape();
db.Flavor();

Console.WriteLine(
"==============================");

Console.WriteLine(
"==========巧克力蛋糕==========");
Cake cake1
= new Chocolate();
decoratorA da1
= new decoratorA(cake1);
decoratorB db1
= new decoratorB(da1);

db1.Shape();
db1.Flavor();
Console.WriteLine(
"==============================");

Console.WriteLine(
"装饰完成!");
Console.Read();
}

}

 

运行结果:

3.验证阶段:

当前目标:增加奶油蛋糕的一个装饰(点蜡烛),证明该模式的适用性;

类结构图:

代码的实现:(在上面代码的基础上附加“点蜡烛”的责任:decoratorC)

 

代码
public class decoratorC : decorator //定义具体装饰类C
{
public decoratorC(Cake cake)
:
base(cake)//调用父类的构造函数
{ }

private string addedState;

public override void Shape()
{
base.Shape();
}

public override void Flavor()
{
base.Flavor();

addedState
= "最后点蜡烛。";
Console.WriteLine(addedState);
}
}
class Program
{
static void Main(string[] args)
{

Cake cake
= new Cream();

decoratorA da
= new decoratorA(cake ); //且有草莓的
decoratorB db = new decoratorB(da); //且有草莓和蜡烛的
decoratorC dc = new decoratorC(db );//且有草莓和点燃的蜡烛的
Console.WriteLine("==========奶油蛋糕===========");

dc.Shape();
dc.Flavor();
//db.Shape();
//db.Flavor();

Console.WriteLine(
"==============================");

Console.WriteLine(
"==========巧克力蛋糕==========");
Cake cake1
= new Chocolate();
decoratorA da1
= new decoratorA(cake1);
decoratorB db1
= new decoratorB(da1);

db1.Shape();
db1.Flavor();
Console.WriteLine(
"==============================");

Console.WriteLine(
"装饰完成!");
Console.Read();
}

}

验证结论:

装饰模式结构图(Struct):
                

在装饰模式中的各个角色有:

  抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。

  具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。

  装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。

  具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。

 

适用性:    需要扩展一个类的功能,或给一个类增加附加责任。

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

需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。 

使用装饰模式的优点和缺点 

  使用装饰模式主要有以下的优点:

  装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。

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

  这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错。

  使用装饰模式主要有以下的缺点:

  由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

 

posted @ 2010-12-15 15:45  天津城建学院软件工程  阅读(555)  评论(1编辑  收藏  举报