OO设计问题接口和类

时间:2015-08-05 19:24:02

标签: java design-patterns interface

我目前正在设计一个纸上应用程序,而且我有点擅长泡菜。

该应用程序的目标是我有汽车工厂,可以给我他们的汽车模型的蓝图。蓝图不是汽车,但它描述了可以从中构建的最终汽车,例如型号名称,车辆上的选项,如空调等。

为此我创建了一个接口ICarBlueprint。此界面上的方法可以包括getModelName()getOptionList()。这些方法必须适用于汽车蓝图的每个实例,无论是欧宝还是大众汽车的蓝图。

工厂,例如欧宝或大众汽车,可以列出他们的汽车蓝图。对于工厂,我创建了一个接口ICarFactory。此接口包含方法getAllBlueprints(),该方法返回ListICarBluePrint个对象。对于Opel工厂,这将是OpelBlueprint个实例,它们实现接口ICarBlueprint

在我的主程序中,我希望获得用户可以选择的所有可能的汽车蓝图。一个例子可能是:

for(ICarFactory f : factories)
    allblueprints.addAll(f.getAllBlueprints());

然后我想迭代那个列表,如果其中一个蓝图是我想要的车,我想建立它。但是,汽车蓝图只能由生成此蓝图的工厂构建。因此,欧宝汽车的蓝图只能由OpelFactory的实例构建,从而实现接口ICarFactory

建造汽车会产生实际的汽车物体。为此,我创建了接口ICar。同样,对于每个工厂,我都会有实现此接口的类。

设计问题我从这里开始。

要构建蓝图,我可以将一个名为build()的方法添加到ICarFactory接口。然后主程序可以简单地选择一个汽车实例,例如goodcarBlueprint并要求汽车工厂建造它。

因此,为了确保蓝图是由正确的工厂构建的,我正在考虑向接口getFactory()ICarBlueprint添加方法build()到{{1}接口。这将允许我在其各自的工厂中建立一个蓝图,如下所示:

ICarFactory

但是,我的直觉是告诉我这个设计非常糟糕。任何有关正确设计方法的帮助都表示赞赏。

4 个答案:

答案 0 :(得分:2)

这是非常主观的,我理解设计不好的感觉,但我不会称之为“非常糟糕”。

对我而言,这听起来像是经典Builder design pattern。在这种情况下,蓝图是构建器。大多数Builders都有一个.build()方法。通过在蓝图上调用.build(),您可以避免从工厂检索蓝图,只需使用它给您的蓝图再次调用工厂。蓝图仍然需要了解自己的工厂,以便它可以让工厂制造汽车。

答案 1 :(得分:2)

我要避免的是ICarBlueprintICarFactory了解其他人。如果您可能拥有多个可以构建相同汽车蓝图的工厂,那么紧密耦合会使未来的变化复杂化。松耦合开辟了可能性。

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);
    }