我目前正在设计一个纸上应用程序,而且我有点擅长泡菜。
该应用程序的目标是我有汽车工厂,可以给我他们的汽车模型的蓝图。蓝图不是汽车,但它描述了可以从中构建的最终汽车,例如型号名称,车辆上的选项,如空调等。
为此我创建了一个接口ICarBlueprint
。此界面上的方法可以包括getModelName()
或getOptionList()
。这些方法必须适用于汽车蓝图的每个实例,无论是欧宝还是大众汽车的蓝图。
工厂,例如欧宝或大众汽车,可以列出他们的汽车蓝图。对于工厂,我创建了一个接口ICarFactory
。此接口包含方法getAllBlueprints()
,该方法返回List
个ICarBluePrint
个对象。对于Opel工厂,这将是OpelBlueprint
个实例,它们实现接口ICarBlueprint
。
在我的主程序中,我希望获得用户可以选择的所有可能的汽车蓝图。一个例子可能是:
for(ICarFactory f : factories)
allblueprints.addAll(f.getAllBlueprints());
然后我想迭代那个列表,如果其中一个蓝图是我想要的车,我想建立它。但是,汽车蓝图只能由生成此蓝图的工厂构建。因此,欧宝汽车的蓝图只能由OpelFactory
的实例构建,从而实现接口ICarFactory
。
建造汽车会产生实际的汽车物体。为此,我创建了接口ICar
。同样,对于每个工厂,我都会有实现此接口的类。
设计问题我从这里开始。
要构建蓝图,我可以将一个名为build()
的方法添加到ICarFactory
接口。然后主程序可以简单地选择一个汽车实例,例如goodcarBlueprint
并要求汽车工厂建造它。
因此,为了确保蓝图是由正确的工厂构建的,我正在考虑向接口getFactory()
和ICarBlueprint
添加方法build()
到{{1}接口。这将允许我在其各自的工厂中建立一个蓝图,如下所示:
ICarFactory
但是,我的直觉是告诉我这个设计非常糟糕。任何有关正确设计方法的帮助都表示赞赏。
答案 0 :(得分:2)
这是非常主观的,我理解设计不好的感觉,但我不会称之为“非常糟糕”。
对我而言,这听起来像是经典Builder design pattern。在这种情况下,蓝图是构建器。大多数Builders都有一个.build()方法。通过在蓝图上调用.build(),您可以避免从工厂检索蓝图,只需使用它给您的蓝图再次调用工厂。蓝图仍然需要了解自己的工厂,以便它可以让工厂制造汽车。
答案 1 :(得分:2)
我要避免的是ICarBlueprint
和ICarFactory
了解其他人。如果您可能拥有多个可以构建相同汽车蓝图的工厂,那么紧密耦合会使未来的变化复杂化。松耦合开辟了可能性。
public interface ICarBuilder {
ICarBlueprint getBlueprint();
ICar build();
}
public class CarBuilder implements ICarBuilder {
private final ICarBlueprint blueprint;
private final Collection<ICarFactory> factories = new ArrayList<ICarFactory>();
public CarBuilder(ICarBlueprint blueprint) {
this.blueprint = blueprint;
}
public ICarBlueprint getBlueprint() {
return blueprint;
}
public CarBuilder addFactory(ICarFactory factory) {
factories.add(factory);
return this;
}
public ICar build() {
// Choose least busy or least cost factory, etc. from factories.
ICarFactory factory = ...;
return factory.build(blueprint);
}
}
现在您可以创建ICarBuilder
的集合并向用户显示蓝图,然后让CarBuilder
决定使用哪个工厂来构建选定的汽车。您甚至可以根据交货时间和成本添加逻辑以显示用户工厂选项,并让他们选择。
答案 2 :(得分:1)
我认为你的设计很好。这一行:
ICar x = goodcarBlueprint.getFactory().build(goodcarBluePrint);
有点冗长,你可能不喜欢goodcarBluePrintFactory出现两次的事实。有一个简单的解决方案,保持你的设计并将这个静态辅助函数添加到ICarFactory:
public static ICar build( ICarBlueprint blueprint) {
return blueprint.getFactory().build(blueprint);
}
当你想从蓝图中建造一辆汽车时,你只会:
ICar x = ICarFactory.build(goodcarBluePrint);
或许您可以改为向ICarBlueprint添加构建方法:
public Icar build() {
getFactory().build(this);
}
您将用作:
ICar x = goodcarBlueprint.build();
我想我最后更喜欢。
答案 3 :(得分:1)
好的,这是我值得的,可能是你违反了得墨忒耳法。
这种设计的复杂性是由于两个要求。蓝图必须知道它属于哪个工厂。您的设计中有一个公共方法getFactory。蓝图的客户是否需要了解整个工厂?我们可以在蓝图中添加一个构建方法,在内部调用工厂的构建,这样可以改善信息隐藏和封装。
ICar x = goodcarBlueprint.getFactory().build(goodcarBluePrint);
减少到
ICar x = goodcarBlueprint.build();
因为我们在蓝图类中有这个额外的方法
public void Build()
{
this.factory.Build(this.BlueprintId);
}
提供所需的信息总是好的,不再需要;如果你没有给收银员钱包,你只需要给他们所需的钱。但是,如果您确实希望整个工厂用于应用程序的其他部分,那么您的原始设计就可以了,但是暴露它可能会产生额外的依赖性,并且很难在以后更改工厂实现,因为客户端将开始依赖它
提到的另一个约束是 - 2.每个蓝图只能由一种工厂使用。我不确定你想要限制多少,但如果你这样做......你可以从每个工厂返回一份IBlueprints列表,但只接受特定类型的蓝图进入工厂。
class OpelFactory : IFactory
{
public IBluePrints GetBluePrints()
{
return this.bluePrints;
}
public void AddBluePrint(IOpelBluePrint bluePrint) //1. we can only add opel blueprints into the opel factory
{
this.bluePrints.Add(bluePrint);
}