根据用户输入使用装饰器设计原则创建 class 的实例

Creating instances of class using decorator design principle based on user input

目前我有这样的可执行代码:

Sandwich sandwich_wTuna_wDoubleCheese = new Cheese(new Cheese(new Tuna(new Bread())));

为了您更好地理解,Sandwich 是由 Bread 和 SandwichDecorator 扩展的抽象 class。三明治装饰器本身又是抽象的,并通过奶酪、金枪鱼、西红柿等进行了扩展。

现在这很好用,但是我有一些面包店应该出售这些使用装饰器设计原理创建的三明治。 我该怎么做?

我希望我可以做这样的事情:

List<String> list=new ArrayList<String>();
list.add("Cheese");
list.add("Cheese");
list.add("Tuna");
Sandwich sandwich_wTuna_wDoubleCheese = bakery1.SellBreads(list);

当然我已经可以传入实例并在面包店函数中进行装饰,但我希望还有其他方法。

你有什么想法,如何解决这个问题?感谢您的帮助和建议。

您可以在 String 上使用 switchList 中的每个元素创建一层三明治装饰。

sandwich = switch (choice) {
    case "Cheese" -> new Cheese(sandwich);
    case "Tuna" -> new Tuna(sandwich);
    default -> throw UnknownSandwichChoice(choice);
};

您可以使用递归或迭代对 List 中的每个元素执行此操作。

这说明您选择的设计模式不符合您的问题。

首先找出你想用对象做什么,然后选择符合这些要求的设计模式。

您为由部分三明治和一个附加层组成的化合物引入了(不同的)抽象(并给这些化合物起了误导性的名称,仅暗示了附加层)。

但是对于排序,您需要层本身的抽象,而这在您的模型世界中不存在。

所以,我会忘记你的装饰器模式,而是将 Sandwich 创建为具有层列表的 class,通常(但不一定?)以 [=11 开头=]层,然后是其他层。然后可以通过在构造函数中提供层列表或在现有三明治上调用 add(Layer) 方法来完成构建。

这看起来像是工厂的工作:)

尝试这样的事情:

public interface IIngredient{}
public abstract class BaseIngredient : IIngredient
{
    private readonly IIngredient _inside;
    protected BaseIngredient(IIngredient inside)
    {
        _inside = inside;
    }
}

public class Tuna : BaseIngredient
{
    public Tuna(IIngredient inside) : base(inside)
    {
    }
}
public class Cheese : BaseIngredient
{
    public Cheese(IIngredient inside) : base(inside)
    {
    }
}
public class Bread : BaseIngredient
{
    public Bread(IIngredient inside) : base(inside)
    {
    }
}


public class IngredientFactory
{
    private readonly Dictionary<string, Func<IIngredient, IIngredient>> _ctors;

    public IngredientFactory()
    {
        _ctors = new Dictionary<string, Func<IIngredient, IIngredient>>()
        {
            {"tuna", (i) => new Tuna(i)},
            {"cheese", (i) => new Cheese(i)},
            {"bread", (i) => new Bread(i)},
        };
    }

    public IIngredient Create(string name, IIngredient inside)
    {
        if(!_ctors.ContainsKey(name))
            throw new ArgumentOutOfRangeException(nameof(name), "invalid ingredient");
        return _ctors[name](inside);
    }
}

在这种情况下,成分类型是硬编码的,但切换到更动态的方法会很容易。一个选项是扫描程序集以查找实现 IIngredient 接口的类型。

成分名称也可以遵循约定并匹配 class 的小写版本。

那么你所要做的就是这样:

List<String> list = new List<String>();
list.Add("Cheese");
list.Add("Cheese");
list.Add("Tuna");

IIngredient result = null;

var factory = new IngredientFactory();
foreach (var name in list)
{
    result = factory.Create(name, result);
}