装饰图案帮助

时间:2011-01-30 06:57:53

标签: c# design-patterns

我正在研究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);
        }
    }
}

这是正确的方法吗?

1 个答案:

答案 0 :(得分:2)

是的,这是一个合适的“装饰”实现。我唯一要问的是你是否真的需要继承Form,或者实施IPhoto是否足够。只能通过更多背景来回答。

此外,如果某些现有值在某处可用,则硬编码(维度?)值看起来可能会有更好的方法。

这个例子本身很不寻常 - 你必须介绍这个界面,这正是你试图避免的变化。并且类型处理事件本身,这是不好的做法。我几乎想知道他们是否希望你挂钩到事件管道,但那不是真正的装饰者。

我怀疑他们希望你对Form进行编码,而不是你引入的IPhoto,这将允许你装饰很多东西。但是你需要在Form上调用一个已知方法,例如Paint() - 除了这里是一个事件,而不是一个方法,所以名称会有所不同。我们可以再次挂钩事件,但这不是经典的装饰用法。