用于装饰图案的观察者模式

时间:2011-01-14 23:59:47

标签: design-patterns uml decorator

我想制作一个为饮料订单输入系统的程序。 (我可能会做描述,费用)

我想使用Decorator模式和观察者模式。 我做了一个UML绘图并将其保存为图片以便于查看。这个网站不会让我上传一个单词doc所以我必须上传一张图片 - 我希望它很容易看到....

在进入编码部分之前,我需要知道我是否正确地进行了UML /设计模式。

Beverage是我的抽象组件类。 浓咖啡,houseblend,darkroast是我的具体课程..

我也有一个调味品装饰类 牛奶,摩卡,大豆,鞭。会是我的观察者吗?因为他们会对成本的数据变化感兴趣吗?

现在,浓缩咖啡,温室咖啡等是否是我的主题,调味品是我的观察者? 我的理论是,成本是变化,调味品需要知道变化吗?

所以,主题= esspresso,houseblend,darkroast等.//他们持有成本()

观察者=牛奶,摩卡,大豆,鞭子? //他们持有费用()

将是具体的组成部分 牛奶,摩卡,大豆,鞭?将是装饰者!

因此,遵循良好的软件工程实践“设计界面而非实现”或“识别那些不会改变的东西”

我需要一个costbehavior接口吗?

如果你看一下UML,你会看到我要去哪里,看看我是否正确实现了观察者+装饰者模式?我认为装饰者是正确的。


因为,图片不是很容易看到我会详细说明这里的类:

饮料类(注册观察者,删除观察者,通知观察者,描述)

这些课程是具体的饮料课程

espresso,houseblend,darkroast,decaf(cost,getdescription,setcost,costchanged)

interface observer class(update)// cost?

interface costbehavior class(cost)//因为这会改变吗?

condiment decorator class(getdescription)

链接到2接口和装饰器的具体类是: 牛奶,摩卡,大豆,鞭(成本,getdescription,更新) 这些是我的装饰/包装类。

谢谢..

alt text

有没有办法让这张照片更大?

3 个答案:

答案 0 :(得分:1)

我绝对不是设计模式专家,但我觉得你在做这个比它需要的更复杂。另外,我不是UML专家,但你是否将每种咖啡类型作为一个单独的类?我认为让饮料类具有类型属性/属性更有意义,然后在其中注入“成本细节”类,这将允许这些饮料报告正确的价格。

答案 1 :(得分:1)

我可以看到装饰器在这里发挥作用,但我不太确定在这里使用观察者。这似乎是被迫的。

有几件事:

  1. CondimentDecorator需要一个饮料来装饰。它不会显示在您的UML中。可以把它想象成一个包装器,类似于适配器模式。包装器需要包装的东西。你显然没有表现出来。
  2. 在您的成本行为界面上,为什么混凝土装饰商会实施它,但混凝土饮料却没有,但饮料还有成本呢?我只是从成本行为界面继承饮料界面并完成它。
  3. #2也适用于getDescription方法...创建IDescribable?或某事,并有饮料工具。装饰者将通过继承获得它。
  4. 你需要说服我为什么调味品需要知道什么时候价格变化?目前,这似乎有点逼迫我。我不知道这里需要观察者(逻辑/设计方面)。在我看来,除了你必须拥有它之外,你想要将观察者模式强加于这个设计中。对于刚学习设计模式的人来说,这是一个经典的模式。不要试图冒犯,只是陈述事实。我曾经也是这样一个人:)。
  5. 我的建议是再次阅读Head First Design Pattern一书(我认为你得到这个例子:),非常相似的领域)并更好地理解这两种模式以及何时使用它们。

    以下是装饰者和观察者一起工作的例子。饮料组合是装饰者的实施。订购系统是观察者(订单将通知寻呼机,寻呼机将执行某些操作)。这里的场景是StarBuck咖啡店,他们会给你一个寻呼机,这样你就可以在你的饮料处理过程中做些什么,一旦饮料准备好,你就会得到寻呼机的通知。

    将示例保存为drink.cs,您可以使用csc轻松编译它(C:\ Windows \ Microsoft.Net \ Framework \ v3 .... \ csc / target:exe /out:drink.exe drink.cs )并运行它或使用VS或其他:)。

    using System;
    using System.Collections.Generic;
    
    public interface IBeverage
    {
      string GetDescription();
      decimal GetCost();
    }
    
    public abstract class Beverage : IBeverage
    {
      protected string _name;
      protected decimal _cost;
    
      public Beverage(string name, decimal cost)
      {
         _name = name;
         _cost = cost;
      }
    
      public virtual string GetDescription()
      {
        return _name;
      }
    
      public virtual decimal GetCost()
      {
        return _cost;
      }
    }
    
    public class Macchiato : Beverage
    {
      public Macchiato() : base("Macchiato", 3.50m) {}
    }
    
    public abstract class BeverageDecorator : Beverage
    {
      IBeverage _baseBeverage;
    
      public BeverageDecorator(IBeverage baseBeverage) : base("", 0m)
      {
        _baseBeverage = baseBeverage;
      }
    
      public override string GetDescription()
      {
        return _name + " " + _baseBeverage.GetDescription();
      }
    
      public override decimal GetCost()
      {
        return _cost + _baseBeverage.GetCost();
      }
    }
    
    public class Caramel : BeverageDecorator
    {
      public Caramel(IBeverage baseBeverage) : base(baseBeverage) 
      {
         _name = "Caramel";
         _cost = 0.50m;
      }
    }
    
    public class Venti : BeverageDecorator
    {
      public Venti(IBeverage baseBeverage) : base(baseBeverage)
      {
         _name = "Venti";
         _cost = 1.00m;
      }
    }
    
    public class Iced : BeverageDecorator
    {
      public Iced(IBeverage baseBeverage) : base(baseBeverage)
      {
        _name = "Iced";
        _cost = 0.25m;
      }
    }
    
    public class Order
    {
      IBeverage _beverage;
      IPager _pager;
    
      public Order(IBeverage beverage, IPager pager)
      {
        _beverage = beverage;
        _pager = pager;
      }
    
      public IPager Pager
      {
        get { return _pager; }
      }
    
      public IBeverage Beverage
      {
        get { return _beverage; }
      }
    }
    
    public class OrderProcessing
    {
        Queue<Order> orders = new Queue<Order>();
    
        public void NewOrder(IBeverage beverage, IPager pager)
        {
          orders.Enqueue(new Order(beverage, pager));
        }
    
        public void ProcessOrder()
        {
          if (orders.Count > 0)
          {
            var order = orders.Dequeue();
            order.Pager.Update(order);
          }
        }
    }
    
    public interface IPager
    {
      void Update(Order order);
    }
    
    public class VibratingPager : IPager
    {
      string _number;
    
      public VibratingPager(string number)
      {
        _number = number;
      }
    
      public void Update(Order order)
      {
        Console.WriteLine("BUZZZ");
        Console.WriteLine("Your {0} is ready.  Please pay {1} at the cashier after picking it up.", order.Beverage.GetDescription(),order.Beverage.GetCost());
      }
    }
    
    public class Program
    {
      public static void Main(string[] args)
      {  
        var orders = new OrderProcessing();
        var pager1 = new VibratingPager("1");
        var pager2 = new VibratingPager("2");    
    
        orders.NewOrder(new Iced(new Venti(new Caramel(new Macchiato()))), pager1);
        orders.NewOrder(new Venti(new Macchiato()), pager2);
    
        orders.ProcessOrder();
        orders.ProcessOrder();
      }
    }
    

答案 2 :(得分:0)

没有。这根本不对。对不起,但事实并非如此。该图说,一切都是饮料,在某些情况下是很多次。显然,这些白色三角形中的一些应该是钻石,大多数可能是黑色。你使用的唯一关系是继承,这显然不是你的意图。

我的设计理念,期间也存在严重问题,但我想这是另一个讨论。对于刚从设计开始的人来说,你所做的一切都是不同寻常的(每个人都开始严肃地对待每一件该死的东西),所以我不会为此感到难过。至少你在考虑设计,这是一件非常好的事情。


回复评论:

什么都没有,在需要的地方应用。当它应用于不适用的地方时相当多。这里根本不需要它。而且,你做错了。奶油不是咖啡的装饰者(我认为这就是你想要做的)咖啡加奶油可能......但那仍然是过度设计。

装饰者为它正在装饰的东西添加行为。假设您有一个消息类和一个显示输出的打印函数:

struct message
{
  virtual void print() = 0;
};

struct concrete_message : message
{
  void print() { std::cout << my_message << std::endl; }
};

现在让我们说你想让它们中的一些缩进。你可以通过使用“装饰器”来做到这一点,它包含一个消息:

struct tabbed_message
{
  tabbed_message(message * msg) : my_message(msg) {}
  void print() { std::cout << "\t; my_message->print(); }
};

了解如何更改任何具体消息的行为而无需更改原始消息?

你用咖啡/调味品做的东西不是这样的。调味品只是你放入咖啡的东西。有或没有奶油的咖啡之间的行为没有区别(例如)。如果你想加入奶油,那么你只需将它与一杯咖啡联系起来,当你问杯子的含量是多少时,你可以用它来计算。