Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java中装饰器和状态模式的结合——关于面向对象设计的问题 我正在解决一个问题,我认为它最适合装饰家和国家模式。高级设置类似于三明治制作机和分配器,在那里我有一定量的配料和几种不同类型的三明治。每个中介都有与其相关的成本。客户将使用机器选择配料来制作特定的swndwich,并由机器分配_Java_Oop_Design Patterns_Decorator_State Pattern - Fatal编程技术网

java中装饰器和状态模式的结合——关于面向对象设计的问题 我正在解决一个问题,我认为它最适合装饰家和国家模式。高级设置类似于三明治制作机和分配器,在那里我有一定量的配料和几种不同类型的三明治。每个中介都有与其相关的成本。客户将使用机器选择配料来制作特定的swndwich,并由机器分配

java中装饰器和状态模式的结合——关于面向对象设计的问题 我正在解决一个问题,我认为它最适合装饰家和国家模式。高级设置类似于三明治制作机和分配器,在那里我有一定量的配料和几种不同类型的三明治。每个中介都有与其相关的成本。客户将使用机器选择配料来制作特定的swndwich,并由机器分配,java,oop,design-patterns,decorator,state-pattern,Java,Oop,Design Patterns,Decorator,State Pattern,到目前为止,我已经使用装饰图案创建了配料和不同类型的三明治: public abstract class Sandwich { String description = "Unknown Sandwich"; public String getDescription(){ return description; } public double cost(){ return 0.0; } } 每个成分的建模如下: pub

到目前为止,我已经使用装饰图案创建了配料和不同类型的三明治:

public abstract class Sandwich {
    String description = "Unknown Sandwich";

    public String getDescription(){
        return description;
    }

    public double cost(){
        return 0.0;
    }
}
每个成分的建模如下:

public abstract class Ingredient extends Sandwich {
    public abstract String getDescription();
}
此外,一种具体成分是:

public class Cheese extends Ingredient {
    private Sandwich sandwich;

    public Cheese(Sandwich sandwich){
        this.sandwich = sandwich;
    }

    public String getDescription() {
        return sandwich.getDescription() + ", cheese";
    }

    public double cost() {
        return 0.25 + sandwich.cost();
    }
}
特定类型的三明治可以这样建模:

public class BLT extends Sandwich {
    public BLT(){
        description = "Bacon, Lettuce and Tomato";
    }
}
Sandwich order_a_blt = new Tomato(new Lettuce(new Bacon(new Bread(new BLT()))));
因此,客户会创建一个特定的三明治,如下所示:

public class BLT extends Sandwich {
    public BLT(){
        description = "Bacon, Lettuce and Tomato";
    }
}
Sandwich order_a_blt = new Tomato(new Lettuce(new Bacon(new Bread(new BLT()))));
作为下一步,我将创建一个分配器对象,该对象将作为一台自动机器,预加载特定数量的配料(以通用单位计量),用户可以按下按钮选择一个预设选项:

比如说

  • BLT:1单位西红柿,1单位西红柿 生菜,1份培根,1份面包
  • SUB:1个肉丸,1个奶酪, 1份意大利沙司,1份面包
  • 等等
我的配药机将预装每个配料的固定数量的单位

  • 番茄:10
  • 生菜:10
  • 培根:10
  • 等等
以及供用户选择特定类型三明治的按钮列表:

  • 1-BLT
  • 2-SUB
  • 3-BBQ
  • 等等
这个想法是为了跟踪配料的内部容量,并能够告诉用户,比如说,我们没有足够的培根来制作另一个BLT

现在,我最初的想法是基于状态设计模式创建分发器对象,但在尝试将配料类的对象与分发器类中的某种存储组合起来时遇到了一个问题。首先,我通过一个带有名称/值的映射来匹配配料类型/配料数量。但我不知道如何将这些模式组合在一起,以便每次使用后自动递减

您是否对如何实施这一概念有一个总体想法?首先,我在装饰和状态模式方面走对了吗?有没有更有效的方法?我希望我已经把问题解释清楚了

谢谢你的指点,我很欣赏你的想法。三明治和奶酪是“has-a”关系,所以三明治不应该是奶酪之母

不确定你在这条线上做什么:

Sandwich order_a_blt = new Tomato(new Lettuce(new Bacon(new Bread(new BLT()))));
从逻辑上讲,为什么要创建一个番茄对象并传递一个莴苣? 西红柿、生菜。。。。etc应扩展成分

我会这样做

class Sandwich{ public Sandwich(Ingredients ...ing){}}
在每个配料类中,我会在番茄中放入一个静态变量,称之为tomatoCount,然后在创建分配器时初始化它,每次创建一个新番茄时,它都会递减。如果它达到零,那么西红柿阶级就会抱怨三明治和奶酪是“has-a”关系,所以三明治永远不应该是奶酪的母体

不确定你在这条线上做什么:

Sandwich order_a_blt = new Tomato(new Lettuce(new Bacon(new Bread(new BLT()))));
从逻辑上讲,为什么要创建一个番茄对象并传递一个莴苣? 西红柿、生菜。。。。etc应扩展成分

我会这样做

class Sandwich{ public Sandwich(Ingredients ...ing){}}

在每个配料类中,我会在番茄中放入一个静态变量,称之为tomatoCount,然后在创建分配器时初始化它,每次创建一个新番茄时,它都会递减。如果它达到零,那么番茄类会抱怨装饰器模式不适合您的问题。成分并不会给三明治增加新的行为,更不用说将三明治和is-a关系中的(三明治)成分联系起来已经有点做作了。(嵌套实例化在必须动态执行之前看起来很酷。)

三明治有配料/馅料/调味品。为配料建立一个类层次结构,并使用复合模式将其与三明治折叠在一起

public abstract class Ingredient {
    protected Ingredient(Object name) { ... }
    public String name() { ... }
    public abstract String description();
    public abstract double cost();
}

public Cheese extends Ingredient {
    public Cheese() { super("Cheese"); }
    public String description() { ... }
    public double cost() { return 0.25; }
|

public abstract class Sandwich {
   public abstract double cost();
   public Set<Ingredient> fillings() { ... }
   public boolean addFilling(Ingredient filling) { ... }
   public boolean removeFilling(Ingredient filling) { ... }
   public double totalFillingsCost();
   ...
}

public class SubmarineSandwich extends Sandwich {
   public SubmarineSandwich() { ... }
   public double cost() { return 2.50 + totalFillingsCost(); }   
}

public enum SandwichType { 
    Custom,
    Blt,
    Sub,
    ...
}

public class SandwichFactory  {
    public Sandwich createSandwich(SandwichType type) {
        switch (type) {
            case Custom:
                return new Sandwich() { public double cost() { return 1.25; } };
            case Blt:
                return new BaconLettuceTomatoSandwich();
            case Sub:
               return new SubmarineSandwich();
            ....
        }
    }
}

e、 例如,分配器的内部状态没有显著差异,这就要求其公共接口具有多态性行为。

装饰器模式不适合您的问题。成分并不会给三明治增加新的行为,更不用说将三明治和is-a关系中的(三明治)成分联系起来已经有点做作了。(嵌套实例化在必须动态执行之前看起来很酷。)

三明治有配料/馅料/调味品。为配料建立一个类层次结构,并使用复合模式将其与三明治折叠在一起

public abstract class Ingredient {
    protected Ingredient(Object name) { ... }
    public String name() { ... }
    public abstract String description();
    public abstract double cost();
}

public Cheese extends Ingredient {
    public Cheese() { super("Cheese"); }
    public String description() { ... }
    public double cost() { return 0.25; }
|

public abstract class Sandwich {
   public abstract double cost();
   public Set<Ingredient> fillings() { ... }
   public boolean addFilling(Ingredient filling) { ... }
   public boolean removeFilling(Ingredient filling) { ... }
   public double totalFillingsCost();
   ...
}

public class SubmarineSandwich extends Sandwich {
   public SubmarineSandwich() { ... }
   public double cost() { return 2.50 + totalFillingsCost(); }   
}

public enum SandwichType { 
    Custom,
    Blt,
    Sub,
    ...
}

public class SandwichFactory  {
    public Sandwich createSandwich(SandwichType type) {
        switch (type) {
            case Custom:
                return new Sandwich() { public double cost() { return 1.25; } };
            case Blt:
                return new BaconLettuceTomatoSandwich();
            case Sub:
               return new SubmarineSandwich();
            ....
        }
    }
}
e、 例如,分配器的内部状态没有显著差异,这就要求其公共接口具有多态性行为

  • 配料不是三明治
  • 最好将原料价格外部化,以允许其灵活变化
  • 最好是制作三明治 基于its的运行时描述 而不是硬编码的成分 在班级层面
  • 食材应该什么都不知道 关于三明治 因此,我将提供以下解决方案:

    package com;
    
    public enum Ingredient {
    
     CHEESE, TOMATO, LETTUCE, BACON, BREAD, MEATBALL, ITALIAN_SAUCE;
    
     private final String description;
    
     Ingredient() {
      description = toString().toLowerCase();
     }
    
     Ingredient(String description) {
      this.description = description;
     }
    
     public String getDescription() {
      return description;
     }
    }
    
    
    package com;
    
    import static com.Ingredient.*;
    
    import java.util.*;
    import static java.util.Arrays.asList;
    
    public enum SandwitchType {
    
     BLT(
       asList(TOMATO, LETTUCE, BACON, BREAD),
                 1  ,    1,      1  ,   1
     ),
     SUB(
       asList(MEATBALL, CHEESE, ITALIAN_SAUCE, BREAD),
                  1   ,    1  ,      1       ,   1
     );
    
     private final Map<Ingredient, Integer> ingredients = new EnumMap<Ingredient, Integer>(Ingredient.class);
     private final Map<Ingredient, Integer> ingredientsView = Collections.unmodifiableMap(ingredients);
    
     SandwitchType(Collection<Ingredient> ingredients, int ... unitsNumber) {
      int i = -1;
      for (Ingredient ingredient : ingredients) {
       if (++i >= unitsNumber.length) {
        throw new IllegalArgumentException(String.format("Can't create sandwitch %s. Reason: given ingedients "
          + "and their units number are inconsistent (%d ingredients, %d units number)", 
          this, ingredients.size(), unitsNumber.length));
       }
       this.ingredients.put(ingredient, unitsNumber[i]);
      }
     }
    
     public Map<Ingredient, Integer> getIngredients() {
      return ingredientsView;
     }
    
     public String getDescription() {
      StringBuilder result = new StringBuilder();
      for (Ingredient ingredient : ingredients.keySet()) {
       result.append(ingredient.getDescription()).append(", ");
      }
    
      if (result.length() > 1) {
       result.setLength(result.length() - 2);
      }
      return result.toString();
     }
    }
    
    
    package com;
    
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    import java.util.concurrent.ConcurrentMap;
    
    public class PriceList {
    
     private static final int PRECISION = 2;
    
     private final ConcurrentMap<Ingredient, Double> prices = new ConcurrentHashMap<Ingredient, Double>();
    
     public double getPrice(SandwitchType sandwitchType) {
      double result = 0;
      for (Map.Entry<Ingredient, Integer> entry : sandwitchType.getIngredients().entrySet()) {
       Double price = prices.get(entry.getKey());
       if (price == null) {
        throw new IllegalStateException(String.format("Can't calculate price for sandwitch type %s. Reason: "
          + "no price is defined for ingredient %s. Registered ingredient prices: %s",
          sandwitchType, entry.getKey(), prices));
       }
       result += price * entry.getValue();
      }
      return round(result);
     }
    
     public void setIngredientPrice(Ingredient ingredient, double price) {
      prices.put(ingredient, round(price));
     }
    
     private static double round(double d) {
      double multiplier = Math.pow(10, PRECISION);
      return Math.floor(d * multiplier + 0.5) / multiplier;
     }
    }
    
    
    package com;
    
    import java.util.Map;
    import java.util.EnumMap;
    
    public class Dispenser {
    
     private final Map<Ingredient, Integer> availableIngredients = new EnumMap<Ingredient, Integer>(Ingredient.class);
    
     public String buySandwitch(SandwitchType sandwitchType) {
      StringBuilder result = new StringBuilder();
      synchronized (availableIngredients) {
    
       Map<Ingredient, Integer> buffer = new EnumMap<Ingredient, Integer>(availableIngredients);
       for (Map.Entry<Ingredient, Integer> entry : sandwitchType.getIngredients().entrySet()) {
        Integer currentNumber = buffer.get(entry.getKey());
        if (currentNumber == null || currentNumber < entry.getValue()) {
         result.append(String.format("not enough %s (required %d, available %d), ",
           entry.getKey().getDescription(), entry.getValue(), currentNumber == null ? 0 : currentNumber));
         continue;
        }
        buffer.put(entry.getKey(), currentNumber - entry.getValue());
       }
    
       if (result.length() <= 0) {
        availableIngredients.clear();
        availableIngredients.putAll(buffer);
        return "";
       }
      }
      if (result.length() > 1) {
       result.setLength(result.length() - 2);
      }
      return result.toString();
     }
    
     public void load(Ingredient ingredient, int unitsNumber) {
      synchronized (availableIngredients) {
       Integer currentNumber = availableIngredients.get(ingredient);
       if (currentNumber == null) {
        availableIngredients.put(ingredient, unitsNumber);
        return;
       }
       availableIngredients.put(ingredient, currentNumber + unitsNumber);
      }
     }
    }
    
    
    package com;
    
    public class StartClass {
     public static void main(String[] args) {
      Dispenser dispenser = new Dispenser();
      for (Ingredient ingredient : Ingredient.values()) {
       dispenser.load(ingredient, 10);
      }
      PriceList priceList = loadPrices();
      while (true) {
       for (SandwitchType sandwitchType : SandwitchType.values()) {
        System.out.printf("About to buy %s sandwitch. Price is %f...",
          sandwitchType, priceList.getPrice(sandwitchType));
        String rejectReason = dispenser.buySandwitch(sandwitchType);
        if (!rejectReason.isEmpty()) {
         System.out.println(" Failed: " + rejectReason);
         return;
        }
        System.out.println(" Done");
       }
      }
     }
    
     private static PriceList loadPrices() {
      PriceList priceList = new PriceList();
      double i = 0.1;
      for (Ingredient ingredient : Ingredient.values()) {
       priceList.setIngredientPrice(ingredient, i);
       i *= 2;
      }
      return priceList;
     }
    }
    
    package-com;
    公共枚举成分{
    奶酪,番茄,生菜,培根,面包,肉丸,意大利沙司;
    私有最终字符串描述;
    成分(){
    description=toString().toLowerCase();
    }
    成分(字符串描述){
    this.description=描述;
    }
    公共字符串getDescription(){
    返回说明;
    }
    }
    包装组件;
    导入静态com.Component.*;
    导入java.util.*;
    导入静态java.util.Arrays.asList;
    公共枚举类型{
    BLT(
    asList(番茄、生菜、培根、面包),
    1  ,    1,      1  ,   1
    ),
    潜艇(
    asList(肉丸、奶酪、意大利沙司、,