在哪里创建AbstractFactory

时间:2009-07-22 15:41:39

标签: c# java design-patterns oop instantiation

在抽象工厂中,您声明一个负责创建对象的类型。

这样可以防止需要这样的开关:

 if( type == ONE ) {
     doOne();
  } else if( type == TWO ) { 
     doTwo();
  } etc. 

或者相同:

 switch( type ) {
     case ONE: doOne(); break;
     case TWO: doTwo(); break;
     etc....
  }

进入这个:

   MyAbstractFactory factoryInstance = ... ? 

   SomeObject object = factoryInstance.createObject();

   object.doX();

据我所知,AbstractFactory将创建正确的对象,而这个对象将以多态方式执行正确的行为。

然后,如果您在程序中使用该对象10-20或100次,则不必每次都重复切换。您只需执行相应的方法并留下多态来完成工作。

   object.doY();

   object.doZ();

添加新类型就像创建新的混凝土工厂一样简单。

这一切对我来说都很清楚。但是......

首先在哪里或如何创建具体工厂(一般而言)?

我总是使用一个单点(通常在main()方法或Configuration.init()方法中),而这反过来确实有if / else | switch构造,这是不可避免的,但至少只使用它一旦。

然而,我“本能地”(或通过常识)做到了这一点,但从未读过任何描述模式应该创建的文档。

:)

5 个答案:

答案 0 :(得分:1)

Abstract Factory有点像工厂的工厂。它提供了一种在不知道具体类型的情况下创建相关对象的方法。您仍然需要知道哪个“抽象工厂”要“实例化”,这意味着抽象工厂的具体实现基于某个变量进行实例化。

例如,假设您是汽车/卡车制造商,您有 CarSeats CarStereo 等项目,您还有 TruckSeats TruckStereo ,他们都实现了一些共同的界面,他们都说 IVehicleItem 。此时,您可以拥有两个工厂 TruckFactory CarFactory ,它们都实现了一个抽象工厂,比如 VehicleFactory 。现在你可以做这样的事情了。

VehicleFactory carFactory = new CarFactory();
IVehicle car = new Car(carFactory);

VehicleFactory truckFactory = new TruckFactory();
IVehicle truck = new Truck(truckFactory);

正如您所见,我在需要时实例化相应的工厂。这是我现在能想到的最好的例子,但我认为工厂类中的switch语句或if语句都不是很糟糕。我通常使用Enum来确定我需要哪个课程。

编辑添加:我认为混淆的是人们误解了抽象工厂是什么。也许就是我的“downvote”的情况。 Abstract Factory PatternFactory Method Pattern不同。

Wiki - 抽象工厂模式是一种复合模式结合使用工厂模式和界面模式

你提到不是Wiki,或GoF..etc显示如何实例化具体类。这是不正确的,如果你查看维基百科的工厂方法模式文章,你会看到这个小片段

public static ImageReader getImageReader(InputStream is) {    

 int imageType = figureOutImageType(is);

   switch(imageType) {
            case ImageReaderFactory.GIF:
                return new GifReader(is);
            case ImageReaderFactory.JPEG:
                return new JpegReader(is);
            // etc.
        }
}

如果您阅读维基百科的抽象工厂模式文章,您将看到这一小段代码。

public static GUIFactory createOsSpecificFactory() {
        int sys = readFromConfigFile("OS_TYPE");
        if (sys == 0) {
            return new WinFactory();
        } else {
            return new OSXFactory();
        }
    }

重点是没有“正确”的方式。您可以根据您在应用程序中尝试执行的操作来实例化具体类。当然,“if”或“switch”语句是可以避免的。但我个人认为使用它们没有任何问题。

答案 1 :(得分:1)

由于抽象工厂的主要优势在于将工厂创建的具体项目的知识与工厂的客户分开,因此您希望保留这些知识(显然,包括具体的工厂实施)从其余的代码。一种方法是创建一个“FactoryService”,在运行时提供对抽象工厂实例的访问。

您的客户端代码可能如下所示:

FactoryService service = FactoryService.instance();
MyAbstractFactory factory = service.getFactory();
SomeObject obj = factory.createObject();

这样,您隐藏了在服务中实例化工厂的逻辑,例如,服务可以从配置文件中读取类名。

许多框架都有组件生命周期管理,允许创建组件并设置它们的依赖关系(Spring,如上所述,是一个)。如果您想要基于Spring,可以将Spring配置为将工厂的特定实例注入工厂服务。

此方法的另一个优点是可测试性:您可以配置测试运行器以创建模拟工厂并将其注入您的服务。该服务的每个用户都将在不对其代码进行任何更改的情况下接收用于测试目的的模拟工厂。

答案 2 :(得分:0)

有一些方法可以创建不涉及if语句的具体类,但在这种情况下,if语句确实没有错。虽然很多ifs可能是最难读取的代码,但在这种情况下,ifs的目的很简单 - 一个用于创建对象的基本跳转表 - 这使得其他一切变得更简单。它是可读的,没有复杂的逻辑,所以可以接受(恕我直言)。

就替代方案而言,请考虑您是否需要工厂方法。您可能不会,您可能只是在需要它的地方创建具体对象,而不是将参数传递给工厂,可以使用相同的逻辑来确定应该使用给定的对象实现。这并不总是合适的,但有时工厂是一个抽象太过分,你所需要的只是在战略模式中工作的不同对象。

if语句的另一种替代方法是map(C#中的Dictionary,我相信),它基于类型构建器对象或对象本身(如果它是不可变的)或者是一个实例。可以自我复制的对象。

另一种选择是使类型为Enum,其具有可以实例化正确对象的方法。

答案 3 :(得分:0)

我发现当我使用AbstractFactory时有两种情况。

第一种情况是,只有一个具体的类将用于运行一个对象。这个典型的例子是数据库访问代码:您不会在SQL Server中访问您的数据库,然后突然切换到Oracle。具体课程稳定。为此我使用Provider模型:定义ProviderBase类,ProviderCollection类等等。

另一种情况是具体类取决于应用程序的状态。在这种情况下,我通常在抽象基类上提供一个工厂方法,返回适当的具体类。在该方法中,我通常只有一个switch语句来决定实例化哪个具体类。我曾经尝试过其他人建议并存储了集合中所有具体类的副本,但是对于那个特定的应用程序,当时实例化所有这些类的性能是不可接受的。然而,这两种选择都非常有效且相当容易实现。

答案 4 :(得分:0)

在这个实例中使用一些IoC框架是最灵活的解决方案 - 在早期的答案中推荐使用Spring,Google Guice是另一个很好的选择,很容易入手。

但是,如果需要纯Java解决方案,枚举工作真的很棒。请考虑以下示例:

enum FactoryConfig {
  CONFIG_1 {
     IFactory instantiate() {
        return ...
     }
  },
  CONFIG_2 {
     IFactory instantiate() {
        return ...
     }
  },
  CONFIG_3 {
     IFactory instantiate() {
        return ...
     }
  };

  abstract IFactory instantiate();
}
...
// and its usage..

IFactory factory = FactoryConfig.CONFIG_3.instantiate();

有关类似枚举的更多信息,例如herehere