我正在研究Oreilly的例子
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Collections.Generic;
using Given;
// Decorator Pattern Example Judith Bishop August 2007
// Draws a single photograph in a window of fixed size
// Has decorators that are BorderedPhotos and TaggedPhotos that can be composed and added
// in different combinations
namespace Given {
// The original Photo class
public class Photo : Form {
Image image;
public Photo () {
image = new Bitmap("jug.jpg");
this.Text = "Lemonade";
this.Paint += new PaintEventHandler(Drawer);
}
public virtual void Drawer(Object source, PaintEventArgs e) {
e.Graphics.DrawImage(image,30,20);
}
}
}
class DecoratorPatternExample {
// This simple BorderedPhoto decorator adds a colored BorderedPhoto of fixed size
class BorderedPhoto : Photo {
Photo photo;
Color color;
public BorderedPhoto (Photo p, Color c) {
photo = p;
color=c;
}
public override void Drawer(Object source, PaintEventArgs e) {
photo.Drawer(source, e);
e.Graphics.DrawRectangle(new Pen(color, 10),25,15,215,225);
}
}
// The TaggedPhoto decorator keeps track of the tag number which gives it
// a specific place to be written
class TaggedPhoto : Photo {
Photo photo;
string tag;
int number;
static int count;
List <string> tags = new List <string> ();
public TaggedPhoto(Photo p, string t) {
photo = p;
tag = t;
tags.Add(t);
number = ++count;
}
public override void Drawer(Object source, PaintEventArgs e) {
photo.Drawer(source,e);
e.Graphics.DrawString(tag,
new Font("Arial", 16),
new SolidBrush(Color.Black),
new PointF(80,100+number*20));
}
public string ListTaggedPhotos() {
string s = "Tags are: ";
foreach (string t in tags) s +=t+" ";
return s;
}
}
static void Main () {
// Application.Run acts as a simple client
Photo photo;
TaggedPhoto foodTaggedPhoto, colorTaggedPhoto, tag;
BorderedPhoto composition;
// Compose a photo with two TaggedPhotos and a blue BorderedPhoto
photo = new Photo();
Application.Run(photo);
foodTaggedPhoto = new TaggedPhoto (photo,"Food");
colorTaggedPhoto = new TaggedPhoto (foodTaggedPhoto,"Yellow");
composition = new BorderedPhoto(colorTaggedPhoto, Color.Blue);
Application.Run(composition);
Console.WriteLine(colorTaggedPhoto.ListTaggedPhotos());
// Compose a photo with one TaggedPhoto and a yellow BorderedPhoto
photo = new Photo();
tag = new TaggedPhoto (photo,"Jug");
composition = new BorderedPhoto(tag, Color.Yellow);
Application.Run(composition);
Console.WriteLine(tag.ListTaggedPhotos());
}
}
/* Output
TaggedPhotos are: Food Yellow
TaggedPhotos are: Food Yellow Jug
*/
下一步练习
假设Photo类是用Drawer作为普通(非虚拟)编写的 方法,它不能改变。重建示例2-2以使其有效 在此约束下
我该怎么做?
我的方法
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using GivenWihInterface;
namespace GivenWihInterface
{
interface IPhoto
{
void Drawer(object sender, PaintEventArgs e);
}
class Photo : Form, IPhoto
{
Image image;
public Photo()
{
image = new Bitmap(@"c:\users\anishmarokey\documents\visual studio 2010\Projects\Design_Pattern_Decorator\DecoratorPattern_RealExample\Images\apple-6.jpg");
this.Text = "Apple";
this.Paint += new PaintEventHandler(Drawer);
}
public void Drawer(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(image, 20, 20);
}
}
class BorderPhoto : Form, IPhoto
{
IPhoto pho;
Color color;
public BorderPhoto(IPhoto p, Color c)
{
pho = p;
color = c;
this.Paint += new PaintEventHandler(Drawer);
}
public void Drawer(object sender, PaintEventArgs e)
{
pho.Drawer(sender, e);
e.Graphics.DrawRectangle(new Pen(color, 10), 25, 15, 215, 225);
}
}
}
namespace DecoratorPattern_RealExample
{
class DecoratorPatternWithInterface
{
static void Dispaly(GivenWihInterface.IPhoto p)
{
Application.Run((Form)p);
}
static void Main()
{
IPhoto component = new GivenWihInterface.Photo();
Dispaly(component);
component = new GivenWihInterface.Photo();
IPhoto p = new GivenWihInterface.BorderPhoto(component,Color.Red);
Application.Run((Form)p);
}
}
}
这是正确的方法吗?
答案 0 :(得分:2)
是的,这是一个合适的“装饰”实现。我唯一要问的是你是否真的需要继承Form
,或者实施IPhoto
是否足够。只能通过更多背景来回答。
此外,如果某些现有值在某处可用,则硬编码(维度?)值看起来可能会有更好的方法。
这个例子本身很不寻常 - 你必须介绍这个界面,这正是你试图避免的变化。并且类型处理事件本身,这是不好的做法。我几乎想知道他们是否希望你挂钩到事件管道,但那不是真正的装饰者。
我怀疑他们希望你对Form进行编码,而不是你引入的IPhoto,这将允许你装饰很多东西。但是你需要在Form上调用一个已知方法,例如Paint() - 除了这里是一个事件,而不是一个方法,所以名称会有所不同。我们可以再次挂钩事件,但这不是经典的装饰用法。