【问题标题】:decorator pattern in drawing program绘图程序中的装饰器模式
【发布时间】:2026-01-08 14:00:01
【问题描述】:

我想问一些关于装饰器模式的问题。

我正在尝试制作有关绘制形状的软件,例如:线条,矩形...... 当我点击表单中的“行”时,我想应用装饰器模式来生效......这是我的实现装饰器

class Composite
{}
class line, rect...: Composite
{}

interface UserCommand
{
    void Excute();
}

class ClickStyle: UserCommand
{
   Composite Concrete;
   .....
}

class MoveStyle: UserCommand
{
   Composite Concrete;
   ...
}

Composite Line = new Line();
if(LineClick)
Line = new BorderStyle(Line);
if(LineMove)
Line = new MoveStyle(Line);
....
To add Effect 

但是当 User NotClick, NotMove 时如何移除这个 Effect 呢?

经验: 我的线条同时具有点击和移动效果,我点击矩形...如何从线条中移除效果?

【问题讨论】:

  • 您在每次使用实例时构建它们。
  • 这是我认为的第一个想法......但这并不好(许多实例会创建,我无法控制)。希望任何人都可以解释其他想法
  • 我不明白你在说什么。您想添加应用某些效果的装饰器,并且还在寻找一种方法来移除装饰器(如果不再需要这些效果)?

标签: c# design-patterns decorator


【解决方案1】:

尽管装饰器模式非常适合这类系统,但如果您需要能够移除任何当前效果,我认为一个普通的旧修饰符列表会更好地为您服务。所有这些都是意见,而不是基于专业经验。我还假设您有某种Draw()Paint() 循环来重绘“脏”形状

考虑一个基本形状:

public class BaseShape
{
    public List<BaseStyle> Styles {get;}

    //...

    public void Draw()
    {
        this.DrawMe();

        foreach(var style in Styles)
        {
           style.Draw(this);
        }   
    }

    public void AddStyle(BaseStyle style){this.Styles.Add(style);}
    public void RemoveStyle(BaseStyle style){this.Styles.Remove(style);}

    protected abstract void DrawMe(); // Child class (eg Circle) knows how to draw the shape
}

public class BorderStyle : BaseStyle
{
    public override void Draw(BaseShape shape)
    {
       // Draw a border as you would in your decorator.
    }
}

这将允许您添加和删除样式以及共享样式实例,您预先知道样式将是相同的。例如,指示形状被选中/激活的轮廓。

public void Main()
{
    var border = new BorderStyle(); // shared

    var circle = new Circle();
    circle.AddStyle(border);

    var square = new Square();
    square.AddStyle(border);

    // Later you want to remove the border and add a drop shadow:
    square.RemoveStyle(border);
    square.AddStyle(new DropShadowStyle());
}

这也将允许一些优化,例如,如果修改器的属性已更改,则仅重绘修改器。例如,如果边框宽度得到更新。

这很可能也适用于您的命令系统,因为Execute() 可以添加样式,Undo() 可能具有逆算法,即删除样式。

另一个好处(取决于您的应用所允许的)是样式与它们所装饰的内容完全分离。例如,假设用户创建了一个红色的 4px 边框样式并希望将其保存以供将来使用,您可以轻松地序列化此样式并将其用作模板以应用于将来的各种形状。

【讨论】:

    【解决方案2】:

    我认为在您的情况下使用状态模式会更好。每个州都可以有自己的装饰器。希望你有一个想法:

    Composite Line = new Line();
    if(LineClick)
    Line.SetActiveState();
    if(LineMove)
    Line.SetOnMoveState();
    

    SetActiveState() 方法可以是这样的:

    void SetActiveState() {
      this.Composite.Decorator = this.Decorators[StateDecorators.Active];
    }
    

    【讨论】:

    • 我认为这不是绘图应用程序的好方法。他会很快遇到一个 XY 问题,他需要状态 X、Y、Z、XY、XZ、YZ...,具体取决于效果的数量。例如,如果形状必须有轮廓并有阴影,则必须有 OutlineAndShadowState。装饰器模式确实更合适,因为您可以拥有 X、Y、Z,然后以任何方式组合 X(Y(Z))。
    最近更新 更多