我在最近的一次采访中被问到:
三明治应该有两片面包 (每端一个),以及介于两者之间的任何正数奶酪。
Sandwich s = new Sandwich();
s.add(new BreadSlice());
s.add(new CheddarCheese());
s.add(new SwissCheese());
s.add(new BreadSlice());
System.println("My sandwich: "+ s.toString());
您可以使用哪种设计模式来确保实例化的每个三明治都是有效的三明治?
答案 0 :(得分:9)
您可以使用Builder
模式:用于非常复杂的多步骤对象构造,其中构造函数或方法参数的数量可能非常高。
SandwichBuilder sb = new SandwichBuilder();
sb.addFirstBread(new BreadSlice());
sb.addCheese(new Cheese());
...
sb.addLastBread(new BreadSlice());
Sandwich s = sb.getSandwich();
如果在调用SandwichBuilders
时未正确完成,不完整IncompleteSandwichException
可能会抛出某种.getSandwich()
。
注意: 使用正确命名的构造方法,您无需按特定顺序执行任何操作。
或者您可以使用FactoryMethod
模式:当步数适合具有合理数量的参数的单个方法调用时,该对象应保证为完整状态。< / em>的
BreadSlice bs1 = new BreadSlice();
BreadSlice bs2 = new BreadSlice();
List<Cheese> cheeses = new ArrayList<Cheese>();
...
Sandwich s = SandwichBuilder.buildSandwich(bs1, cheeses, bs2);
或使用Constructor
:这是FactoryMethod
模式的专业案例
Sandwich s = new Sandwich(bs1, cheeses, bs2);
重载构造函数以允许添加奶酪:
Sandwich s = new Sandwich(bs1, bs2);
s.addCheese(new CheeseSlice());
...
根据您希望构造的严格程度,有很多方法可以做到这一点。
例如,您可以使Sandwich
实现成为inner class
对象的Factory/Builder
并使其构造函数private
无法正确实例化。
答案 1 :(得分:6)
我认为Builder模式在这里可能是一个不错的选择。
答案 2 :(得分:0)
我已使用
实施了解决方案模板模式。
虽然解决方案是在C#中,但可以很容易地修改它以在Java环境中运行。
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DeliverSandwitch(new MinimumCheese());
DeliverSandwitch(new MixCheese());
DeliverSandwitch(new DoubleSwissCheese());
Console.ReadLine();
}
private static void DeliverSandwitch(BaseSandwitch customSandwitch)
{
Console.WriteLine(customSandwitch.Name);
Console.WriteLine("-----------------------------------");
foreach (string layer in customSandwitch.Layers)
Console.WriteLine(layer);
Console.WriteLine();
Console.WriteLine();
}
public abstract class BaseSandwitch
{
List<string> layers = new List<string>();
protected virtual CheeseType DefaultCheese { get { return CheeseType.PlainCheese; } }
public abstract string Name { get; }
public BaseSandwitch()
{
SandwitchTemplate();
}
private void SandwitchTemplate()
{
AddBaseBread();
AddCheese(DefaultCheese);
AddAdditionalCheese();
AddTopBread();
}
private void AddTopBread()
{
layers.Add("Top bread");
}
public abstract void AddAdditionalCheese();
private void AddBaseBread()
{
layers.Add("Base bread");
}
protected void AddCheese(CheeseType cheeseType)
{
layers.Add(cheeseType.ToString());
}
public IEnumerable<string> Layers { get { return layers; } }
}
class MinimumCheese : BaseSandwitch
{
public override string Name { get { return "Minimum cheese Sandwitch"; }}
public override void AddAdditionalCheese()
{
// I come with no additional cheese
}
// I do not like PlainCheese. Replacing with CheddarCheese
protected override CheeseType DefaultCheese
{
get { return CheeseType.CheddarCheese; }
}
}
/// <summary>
/// I am ok with default cheese and would like to have other cheese as well
/// </summary>
class MixCheese : BaseSandwitch
{
public override string Name { get { return "Mix cheese Sandwitch"; } }
public override void AddAdditionalCheese()
{
AddCheese(CheeseType.CheddarCheese);
AddCheese(CheeseType.SwissCheese);
}
}
class DoubleSwissCheese : BaseSandwitch
{
public override string Name { get { return "Double Swiss Cheese Sandwitch"; } }
public override void AddAdditionalCheese()
{
// Adding another layer of swiss cheese
AddCheese(CheeseType.SwissCheese);
}
// I like swiss cheese by default instead of PlainCheese
protected override CheeseType DefaultCheese
{
get { return CheeseType.SwissCheese; }
}
}
public enum CheeseType { PlainCheese, SwissCheese, CheddarCheese };
}
}