使用装饰模式的观察者模式

我想制定一个程序来完成饮料订单输入系统。 (我可能会做描述,成本)

我想使用装饰者模式和观察者模式。 我制作了UML图纸并将其保存为图片以便于查看。 本网站不会让我作为word文档上传,所以我必须上传图片 - 我希望它可以轻松查看....

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

饮料是我的抽象组件类。 浓咖啡,houseblend,darkroast是我的具体主题类。

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

现在,浓咖啡,houseblend等会成为我的主题,调味品是我的观察者吗? 我的理论是,成本是一个变化,调味品需要知道变化?

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

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

会是具体的组件和牛奶,摩卡,大豆,鞭子? 将是装饰者!

因此,遵循良好的软件工程实践“设计到接口而不是实现”或“识别那些不是那些改变的东西”

我需要一个costbehavior界面吗?

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


因为,图片不是很可见,我会在这里详细说明这些类:

饮料课(注册观察员,删除观察员,通知观察员,说明)

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

espresso,houseblend,darkroast,decaf(成本,getdescription,setcost,costchanged)

接口观察员类(更新)//成本?

接口costbehavior类(成本)//因为这改变?

调料装饰类(getdescription)

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

谢谢..

替代文字

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


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

几件事情:

  • CondimentDecorator需要有一个饮料来装饰。 它不会在你的UML中显示。 把它看作是一个包装器,类似于适配器模式。 包装需要包装。 你显然没有表现出来。
  • 在你的成本行为界面上,为什么具体的装饰者会实现它,但是具体的饮料不会,而且饮料也有成本呢? 我只需要从成本行为界面继承饮料界面,并完成它。
  • #2也适用于getDescription方法...创建一个IDescribable? 或什么东西,并有饮料实施。 装饰者将通过继承获得它。
  • 你需要说服我为什么调味品需要知道价格何时改变? 目前,这似乎有点让我受不了。 我没有看到这里需要观察者(逻辑/设计)。 在我看来,你想强制观察者模式进入这种设计,没有什么好的理由,除非你必须拥有它。 对于刚刚了解设计模式的人来说,这是一种经典的模式。 不要试图冒犯,只是说明事实。 我曾经是这样的人:)。
  • 我的建议是再次阅读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();
      }
    }
    

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


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

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


    回复评论:

    什么都没有,只要在需要的地方应用。 当它应用于不适用的地方时,它有点儿不合适。 这里根本就不需要。 此外,你会做错了。 奶油不是咖啡的装饰者(我想这就是你想要做的)咖啡与奶油可能......但这仍然是过度设计。

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

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

    现在让我们说你想让其中的一些缩进。 你可以通过使用“装饰器”来实现,该装饰器的子类AND包含一条消息:

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

    看看如何改变任何具体信息的行为而不必更改原始信息?

    你对咖啡/调味品的看法并不是这样。 调味品就是你放入咖啡的东西。 例如,一杯带奶油或不含奶油的咖啡在行为上没有区别。 如果你想收取加奶油的费用,那么你只需将它与咖啡杯联系起来,当你询问杯子的数量时,就可以运行一杯咖啡。

    链接地址: http://www.djcxy.com/p/32003.html

    上一篇: Observer pattern used with decorator pattern

    下一篇: Question about decorator pattern and the abstract decorator class?