将装饰器模式应用于表单

dev*_*ium 7 c# design-patterns decorator

我试图将装饰器设计模式应用于以下情况:

我有3种不同的形式:绿色,黄色,红色.

现在,每个表单都可以具有不同的属性集.他们可以禁用最小化框,禁用最大化框,它们可以始终位于顶部.

我尝试通过以下方式对其进行建模:

              Form <---------------------------------------FormDecorator
              /\                                                  /\
     |---------|-----------|               |----------------------|-----------------|
GreenForm  YellowForm   RedForm  MinimizeButtonDisabled MaximizedButtonDisabled AlwaysOnTop
Run Code Online (Sandbox Code Playgroud)

这是我的GreenForm代码:

public class GreenForm : Form {
    public GreenForm() {
        this.BackColor = Color.GreenYellow;
    }

    public override sealed Color BackColor {
        get { return base.BackColor; }
        set { base.BackColor = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

FormDecorator:

public abstract class FormDecorator : Form {
    private Form _decoratorForm;

    protected FormDecorator(Form decoratorForm) {
        this._decoratorForm = decoratorForm;
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是NoMaximizeDecorator:

public class NoMaximizeDecorator : FormDecorator
{
    public NoMaximizeDecorator(Form decoratorForm) : base(decoratorForm) {
        this.MaximizeBox = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以这是运行代码:

static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(CreateForm());
}

static Form CreateForm() {
    Form form = new GreenForm();
    form = new NoMaximizeDecorator(form);
    form = new NoMinimizeDecorator(form);

    return form;
}
Run Code Online (Sandbox Code Playgroud)

问题是我得到的表格不是绿色的,仍然允许我最大化它.它只考虑了NoMinimizeDecorator表单.我理解为什么会发生这种情况,但我无法理解如何使用此模式进行此操作.

我知道可能有更好的方法来实现我想要的.我将这个例子作为尝试将Decorator模式应用于某事.也许这不是我可以使用的最佳模式(如果有的话),这种情况.是否还有其他模式比Decorator更适合实现这一目标?在尝试实现Decorator模式时,我做错了吗?

谢谢

Dat*_*han 6

这里的问题是你实际上并没有实现装饰器模式.为了正确实现模式,您需要子类Form来创建装饰器,然后拦截装饰器上的所有操作并将它们转发到您的私有Form实例.除此之外,除了在FormDecorator构造函数中分配引用之外,您再也不会使用该私有Form实例.最终的结果是你创建一个GreenForm,然后将它包装在一个NoMaximizeDecorator,然后你将其包装在一个NoMinimizeDecorator.但是因为您从未将针对NoMinimizeDecorator包装Form实例的操作转发到包装实例,所以只有NoMinimizeDecorator实例实际将任何行为应用于所使用的实例.这符合您在运行代码时观察到的内容:带有禁用的最小化按钮的标准窗口.

Form在C#中创建装饰器是一个非常糟糕的例子,因为它的大多数属性和方法都是非虚拟的,这意味着如果你通过Form引用访问装饰的表单,你就无法拦截基类的属性 - 你可以'有效地"包裹" Form.

编辑

它发生,我认为声明"形式是用C#创建装饰一个非常糟糕的榜样"真的乞求什么的问题就是一个很好的例子.通常,您将使用装饰器模式来提供自定义接口实现,而无需从头开始实现整个实现.一个非常常见的例子是泛型集合.大多数想要列表功能的东西都不依赖于,例如List<String>,而是依赖于IList<String>.因此,如果您想要一个不接受短于5个字符的字符串的自定义集合,您将使用类似以下内容:

public class MinLengthList : IList<String>
{
    private IList<string> _list;
    private int _minLength;

    public MinLengthList(int min_length, IList<String> inner_list)
    {
        _list = inner_list;
        _minLength = min_length;
    }

    protected virtual void ValidateLength(String item)
    {
        if (item.Length < _minLength)
            throw new ArgumentException("Item is too short");
    }

    #region IList<string> Members

    public int IndexOf(string item)
    {
        return _list.IndexOf(item);
    }

    public void Insert(int index, string item)
    {
        ValidateLength(item);
        _list.Insert(index, item);
    }

    public void RemoveAt(int index)
    {
        _list.RemoveAt(index);
    }

    public string this[int index]
    {
        get
        {
            return _list[index];
        }
        set
        {
            ValidateLength(value);
            _list[index] = value;
        }
    }

    #endregion

    #region ICollection<string> Members

    public void Add(string item)
    {
        ValidateLength(item);
        _list.Add(item);
    }

    public void Clear()
    {
        _list.Clear();
    }

    public bool Contains(string item)
    {
        return _list.Contains(item);
    }

    public void CopyTo(string[] array, int arrayIndex)
    {
        _list.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return _list.Count; }
    }

    public bool IsReadOnly
    {
        get { return _list.IsReadOnly; }
    }

    public bool Remove(string item)
    {
        return _list.Remove(item);
    }

    #endregion

    #region IEnumerable<string> Members

    public IEnumerator<string> GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)_list).GetEnumerator();
    }

    #endregion
}

public class Program
{

    static void Main()
    {
        IList<String> custom_list = new MinLengthList(5, new List<String>());
        custom_list.Add("hi");
    }
}
Run Code Online (Sandbox Code Playgroud)