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
- 等等
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、 例如,分配器的内部状态没有显著差异,这就要求其公共接口具有多态性行为
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(肉丸、奶酪、意大利沙司、,