2015-03-19 4 views
-1

Я реализую шаблон дизайна декоратора. У меня есть требование, когда некоторая комбинация декоратора не должна развлекаться. Пример: см. Главу Первая реализация рисунка декоратора здесь: msdn articleрисунок декоратора, применяющий противопоказания

И скажем, я хочу ограничить комбинацию Мокки и Сои на напитке. то есть либо мокко, либо соя, а не оба. Как мы можем сделать это?

Дайте мне знать, если вам нужна дополнительная информация.

+0

Это побудит зависимости между подтипами декоратора, и вы будете обижать другие принципы проектирования ООП ... в этом случае декоратор не был бы хорошим выбором –

+0

Что вы могли бы do - это шаблон строителя ... строитель может украсить напитки и реализовать такой вид проверки. сделать все подтипы частными и в своем собственном пространстве имен, а строитель - внутренним/общедоступным, и вы там. –

+0

Добавлена ​​возможность реализации –

ответ

0

на мой взгляд, вы можете расширить класс 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"); 
    } 
} 
+0

Но есть ли зависимость между другими декораторами ... Проверка наличия других решений (побуждение других моделей) для поддержания свободной связи. – sanoj

0

Что-то вроде:

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 
+0

неудачный выбор названия пространства имен ... Beverages.Beverages.Expresso, но ok =) –

+0

Все еще плохой выбор. Вы не получаете, какая комбинация вызывает ошибку со стороны пользователя. – Fendy

+0

@Fendy Следовательно, комментарий в блоке if строителя ... –

Смежные вопросы