-
定义
动态地给一个对象增加其他职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更加灵活。
UML类图如下:
其中类和对象的关系为:
1. Component(部件):定义对象的接口,可以给这些对象动态增加职责(方法)。
2. ConcreteComponent(具体部件):定义具体的对象,Decorator可以给它增加额外的职责(方法)。
3. Decorator(装饰抽象类):维护一个内有的Component,并且定义一个与Component接口一致的接口。
4. ConcreteDecorator(具体装饰对象):具体的装饰对象,给内在的具体部件对象增加具体的职责(方法)。
典型应用的顺序图如下:
客户调用具体装饰类的AddOperation方法,而具体装饰类又调用自身具体部件(ConcreteComponent)类的Operation方法。
-
实例1——图书馆中的项目
采用装饰模式为图书馆中的项目(书或影像盘)增加“可借”功能性。
UML类图如下:
//定义抽象类LibraryItem
abstract class LibraryItem
{
private int numCopies;
public int NumCopies
{
get { return numCopies; }
set { numCopies = value; }
}
public abstract void Display();
}
//定义具体的部件类Book
class Book : LibraryItem
{
private string author;
private string title;
public Book(string author, string title, int numCopies)
{
this.author = author;
this.title = title;
this.NumCopies = numCopies;
}
public override void Display()
{
Console.WriteLine("\n书 --------------");
Console.WriteLine(" 作者:{0}",author);
Console.WriteLine(" 书名:{0}", title); ;
Console.WriteLine(" #数量:{0}", NumCopies);
}
}
//定义具体的部件类Video
class Video : LibraryItem
{
private string director;
private string title;
private int playTime;
public Video(string director, string title, int numCopies, int playTime)
{
this.director = director;
this.title = title;
this.playTime = playTime;
this.NumCopies = numCopies;
}
public override void Display()
{
Console.WriteLine("\n影像 --------------");
Console.WriteLine(" 导演:{0}", director);
Console.WriteLine(" 片名:{0}", title); ;
Console.WriteLine(" #数量:{0}", NumCopies);
Console.WriteLine(" 播放时间:{0}", playTime);
}
}
//定义抽象装饰类
abstract class Decorator : LibraryItem
{
protected LibraryItem libraryItem;
public Decorator(LibraryItem libraryItem)
{
this.libraryItem=libraryItem;
}
public override void Display()
{
libraryItem.Display();
}
}
//定义具体装饰类
class Borrowable : Decorator
{
protected ArrayList borrowers = new ArrayList();
//调用父类的构造函数
public Borrowable(LibraryItem libraryItem) : base(libraryItem) { }
public void BorrowItem(string name)
{
borrowers.Add(name);
libraryItem.NumCopies--;
}
public void ReturnItem(string name)
{
borrowers.Remove(name);
libraryItem.NumCopies++;
}
public override void Display()
{
base.Display();
foreach(string borrower in borrowers)
{
Console.WriteLine(" 借出人:{0}", borrower);
}
}
}
//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
//创建Book及Video,并显示出来
Book book = new Book("Schnell", "My Home", 10);
Video video = new Video("Spielberg", "Schindler's list", 23, 60);
book.Display();
video.Display();
//增加video的borrowable属性,然后借出并显示
Console.WriteLine("\n影像增加可借属性");
Borrowable borrowvideo = new Borrowable(video);
borrowvideo.BorrowItem("张三");
borrowvideo.BorrowItem("李四");
borrowvideo.BorrowItem("王五");
borrowvideo.ReturnItem("王五");
borrowvideo.Display();
Console.Read();
}
}
-
优势和缺陷
装饰模式提供了比静态继承更好的柔韧性,它允许开发一系列的功能类用来代替增加对象的行为,这既不会污染原来对象的源码,还能使代码更容易编写,使类更具扩展性,因为变化都是由新的装饰类来完成。还可以建立连接的装饰对象关系链。
需要注意的是,装饰链不宜过长。装饰链太长会使系统花费较长时间用于初始化对象,同时信息在链中的传递也会浪费太多的时间。这个情况好比物品包装,包了一层又一层,大包套小包。另外,如果原来的对象接口发生变化,它所以的装饰类都要修改以匹配它的变化。派生子类会影响对象的内部,而一个Decorator只会影响对象的外表。
-
应用情景
下面的情景很适合应用装饰模式:
1. 你想透明并且动态地给对象增加新的职责(方法),而不会影响其他对象。
2. 你给对象增加的职责在未来会发生变化。
3. 用子类扩展功能不实际的情况下。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:十二.结构型设计模式——Decorator Patten(装饰模式) - Python技术站