我正在實施裝飾者設計模式。我有一個要求,裝飾者的某種組合不應該被娛樂。 示例:請參閱Head Decorator模式的首次實現:msdn article裝飾者模式應用約束
並且可以說我想限制飲料上的Mocha和Soy的組合。即摩卡或大豆,而不是兩者。我們怎麼做到這一點?
讓我知道你是否需要更多信息。
我正在實施裝飾者設計模式。我有一個要求,裝飾者的某種組合不應該被娛樂。 示例:請參閱Head Decorator模式的首次實現:msdn article裝飾者模式應用約束
並且可以說我想限制飲料上的Mocha和Soy的組合。即摩卡或大豆,而不是兩者。我們怎麼做到這一點?
讓我知道你是否需要更多信息。
你可以這樣的方式擴展CondimentDecorator類:
public abstract class CondimentDecorator : Beverage
{
public abstract override string Description { get; }
public abstract override void CheckComponent();
}
和實施,在這種方式使用此方法:
public class Mocha : CondimentDecorator
{
private Beverage beverage;
public Mocha(Beverage beverage)
{
this.beverage = beverage;
CheckComponent();
}
public override double Cost()
{
return (.20 + beverage.Cost());
}
public override string Description
{
get { return beverage.Description + ", Mocha"; }
}
public override void CheckComponent()
{
if (Description.Contains("Soy"))
throw new Exception("Wrong component");
}
}
但其他裝飾器之間有依賴關係......檢查是否有其他解決方案(誘導其他模式)來保持鬆散耦合。 – sanoj 2015-03-19 08:13:29
喜歡的東西:
namespace Beverages
{
public class Builder
{
private static Tuple<Condiments, Condiments>[] notAllowedTogether = new[]
{
new Tuple<Condiments,Condiments>(Condiments.Soy,Condiments.Mocha)
};
public static Beverage Build(Beverages beverage, params Condiments[] condiments)
{
// check if theres a combination that is not allowed
if (notAllowedTogether.Any(na => condiments.Contains(na.Item1) && condiments.Contains(na.Item2)))
{
return null; // or throw exception or anything
}
// creation of the base beverage using reflection "Beverages." is the namespace the classes are defined in
Beverage result = (Beverage)Activator
.CreateInstance(
Type.GetType("Beverages." + beverage.ToString()));
// adding the condiments by calling the constructors of the classes
foreach (Condiments condiment in condiments)
{
result = (Beverage)Type
.GetType("Beverages." + condiment.ToString())
.GetConstructor(new Type[]{typeof(Beverage)})
.Invoke(new object[]{result});
}
return result;
}
}
// in order to decouple the classes from the client
// i have introduced enums containing the classes names
public enum Condiments
{
CoffeeMate,
Soy,
Mocha
}
public enum Beverages
{
Expresso,
HouseBlend,
DarkRoast
}
public abstract class Beverage
{
private string description = "Unknown Beverage";
public abstract double Cost();
public virtual string Description
{
get { return description; }
}
}
public abstract class CondimentDecorator : Beverage
{
public abstract override string Description { get; }
}
class Expresso : Beverage
{
public override double Cost()
{
return 1.99;
}
public override string Description
{
get { return "Expresso"; }
}
}
class HouseBlend : Beverage
{
public override double Cost()
{
return .89;
}
public override string Description
{
get { return "House Blend Coffee"; }
}
}
class DarkRoast : Beverage
{
public override double Cost()
{
return .99;
}
public override string Description
{
get { return "Dark Roast Coffee"; }
}
}
class Mocha : CondimentDecorator
{
private Beverage beverage;
public Mocha(Beverage beverage)
{
this.beverage = beverage;
}
public override double Cost()
{
return (.20 + beverage.Cost());
}
public override string Description
{
get { return beverage.Description + ", Mocha"; }
}
}
class Soy : CondimentDecorator
{
private Beverage beverage;
public Soy(Beverage beverage)
{
this.beverage = beverage;
}
public override double Cost()
{
return (.30 + beverage.Cost());
}
public override string Description
{
get { return beverage.Description + ", Soy"; }
}
}
class CoffeeMate : CondimentDecorator
{
private Beverage beverage;
public CoffeeMate(Beverage beverage)
{
this.beverage = beverage;
}
public override double Cost()
{
return (.15 + beverage.Cost());
}
public override string Description
{
get { return beverage.Description + ", Coffee Mate"; }
}
}
}
用途和樣子:
class Program
{
static void Main(string[] args)
{
//Expresso
Beverage expresso = Builder.Build(Beverages.Beverages.Expresso);
Console.WriteLine(expresso.Description + " $" + expresso.Cost());
Beverage houseBlend = Builder.Build(Beverages.Beverages.HouseBlend,Condiments.Mocha, Condiments.Soy);
if (houseBlend == null)
{
Console.WriteLine("Could not make that beverage");
}
else
{
Console.WriteLine(houseBlend.Description + " $" + houseBlend.Cost());
}
Beverage darkRoast = Builder.Build(Beverages.Beverages.DarkRoast, Condiments.CoffeeMate);
Console.WriteLine(darkRoast.Description + " $" + darkRoast.Cost());
Console.ReadLine();
}
}
輸出:
Expresso $1,99
Could not make that beverage
Dark Roast Coffee, Coffee Mate $1,14
命名空間名稱倒黴的選擇... Beverages.Beverages.Expresso,但確定=) – 2015-03-19 08:31:40
仍然是一個不好的選擇。你不會從用戶那邊得到哪個組合產生錯誤。 – Fendy 2015-03-20 02:21:50
@Fendy因此,在建設者的if塊的評論... – 2015-03-20 04:53:40
這將導致裝飾的亞型之間的依賴關係,你會傷害其他OOP的設計原則......在這種情況下,裝飾將不會是一個很好的選擇 – 2015-03-19 07:39:23
盡你所能做的是建築師的模式......建築師可以裝飾飲料,並可以實施這種檢查。使所有的子類型都是私有的,並且在它自己的命名空間和生成器內部/公共之中,並且你在那裏。 – 2015-03-19 07:44:57
添加了一個可能的實現 – 2015-03-19 08:52:35