我想制作一个为饮料订单输入系统的程序。 (我可能会做描述,费用)
我想使用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,更新) 这些是我的装饰/包装类。
谢谢..
有没有办法让这张照片更大?
答案 0 :(得分:1)
我绝对不是设计模式专家,但我觉得你在做这个比它需要的更复杂。另外,我不是UML专家,但你是否将每种咖啡类型作为一个单独的类?我认为让饮料类具有类型属性/属性更有意义,然后在其中注入“成本细节”类,这将允许这些饮料报告正确的价格。
答案 1 :(得分:1)
我可以看到装饰器在这里发挥作用,但我不太确定在这里使用观察者。这似乎是被迫的。
有几件事:
我的建议是再次阅读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(); }
};
了解如何更改任何具体消息的行为而无需更改原始消息?
你用咖啡/调味品做的东西不是这样的。调味品只是你放入咖啡的东西。有或没有奶油的咖啡之间的行为没有区别(例如)。如果你想加入奶油,那么你只需将它与一杯咖啡联系起来,当你问杯子的含量是多少时,你可以用它来计算。