我从一个网站上阅读设计模式

在那里我读到工厂,工厂方法和抽象工厂,但他们是如此混乱,我不清楚的定义。根据定义

Factory - Creates objects without exposing the instantiation logic to the client and Refers to the newly created object through a common interface. Is a simplified version of Factory Method Factory Method - Defines an interface for creating objects, but let subclasses to decide which class to instantiate and Refers to the newly created object through a common interface. Abstract Factory - Offers the interface for creating a family of related objects, without explicitly specifying their classes.

我还看了其他关于抽象工厂和工厂方法的stackoverflow线程,但那里绘制的UML图使我的理解更加糟糕。

有人能告诉我吗

这三种模式之间有什么不同? 什么时候用哪个? 如果可能的话,还有与这些模式相关的java示例吗?


当前回答

每个设计模式都努力确保编写的工作代码不受影响。我们都知道,一旦我们接触到工作代码,现有的工作流程中就会有缺陷,并且需要进行更多的测试以确保我们没有破坏任何东西。

工厂模式根据输入条件创建对象,从而确保你不需要编写如下代码:

 if (this) {
     create this kind of object 
 } else { 
     that kind of object 
 }

一个很好的例子就是旅游网站。旅游网站只能提供旅行(航班、火车、巴士)或/和提供酒店或/和提供旅游景点套餐。现在,当用户选择下一步时,网站需要决定需要创建什么对象。它是否也只创建travel或hotel对象?

现在,如果你设想在你的投资组合中添加另一个网站,并且你相信同样的核心可以被使用,例如,一个拼车网站,现在可以搜索出租车并在线支付,你可以在你的核心中使用一个抽象工厂。这样一来,你就可以再加入一个出租车和拼车工厂。

这两个工厂之间没有任何关系,所以把它们放在不同的工厂是一个很好的设计。

希望大家都明白了。再次研究这个网站,记住这个例子,希望它会有帮助。我真的希望我已经正确地表示了模式:)。

其他回答

每个设计模式都努力确保编写的工作代码不受影响。我们都知道,一旦我们接触到工作代码,现有的工作流程中就会有缺陷,并且需要进行更多的测试以确保我们没有破坏任何东西。

工厂模式根据输入条件创建对象,从而确保你不需要编写如下代码:

 if (this) {
     create this kind of object 
 } else { 
     that kind of object 
 }

一个很好的例子就是旅游网站。旅游网站只能提供旅行(航班、火车、巴士)或/和提供酒店或/和提供旅游景点套餐。现在,当用户选择下一步时,网站需要决定需要创建什么对象。它是否也只创建travel或hotel对象?

现在,如果你设想在你的投资组合中添加另一个网站,并且你相信同样的核心可以被使用,例如,一个拼车网站,现在可以搜索出租车并在线支付,你可以在你的核心中使用一个抽象工厂。这样一来,你就可以再加入一个出租车和拼车工厂。

这两个工厂之间没有任何关系,所以把它们放在不同的工厂是一个很好的设计。

希望大家都明白了。再次研究这个网站,记住这个例子,希望它会有帮助。我真的希望我已经正确地表示了模式:)。

Factory -分离Factory类来创建复杂的对象。

例如:FruitFactory类来创建Fruit对象

class FruitFactory{

public static Fruit getFruit(){...}

}

工厂方法——不需要为工厂添加一个单独的类,只需在类中添加一个方法作为工厂。

Ex:

Calendar.getInstance() (Java's Calendar)

抽象工厂——工厂中的工厂

比方说,我们想建一家生产电脑零件的工厂。有几种类型的电脑,如笔记本电脑,台式电脑,服务器。

所以对于每一种计算机类型,我们都需要工厂。所以我们创建了一个高级的工厂中的工厂,如下所示

ComputerTypeAbstractFactory.getComputerPartFactory(String computerType) ---> This will return PartFactory which can be one of these ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

现在这3家公司本身也是工厂。(您将处理PartFactory本身,但在底层,将有基于您在抽象工厂中提供的内容的单独实现)

  Interface-> PartFactory. getComputerPart(String s), 
Implementations -> ServerPartFactory, LaptopPartFactory, DesktopPartFactory.

Usage:
new ComputerTypeAbstractFactory().getFactory(“Laptop”).getComputerPart(“RAM”)

EDIT:根据注释中的异议为抽象工厂提供精确的接口。

所有三种Factory类型都做同样的事情:它们是一个“智能构造函数”。

假设您希望能够创建两种水果:Apple和Orange。

工厂

Factory is "fixed", in that you have just one implementation with no subclassing. In this case, you will have a class like this:
class FruitFactory {

  public Apple makeApple() {
    // Code for creating an Apple here.
  }

  public Orange makeOrange() {
    // Code for creating an orange here.
  }

}

用例:在构造函数中构造Apple或Orange都太复杂了。

工厂方法

Factory method is generally used when you have some generic processing in a class, but want to vary which kind of fruit you actually use. So:
abstract class FruitPicker {

  protected abstract Fruit makeFruit();

  public void pickFruit() {
    private final Fruit f = makeFruit(); // The fruit we will work on..
    <bla bla bla>
  }
}

...然后你可以通过在子类中实现一个工厂方法来重用fruitpick . pickfruit()中的通用功能:

class OrangePicker extends FruitPicker {

  @Override
  protected Fruit makeFruit() {
    return new Orange();
  }
}

抽象工厂

Abstract factory is normally used for things like dependency injection/strategy, when you want to be able to create a whole family of objects that need to be of "the same kind", and have some common base classes. Here's a vaguely fruit-related example. The use case here is that we want to make sure that we don't accidentally use an OrangePicker on an Apple. As long as we get our Fruit and Picker from the same factory, they will match.
interface PlantFactory {
  
  Plant makePlant();

  Picker makePicker(); 

}

public class AppleFactory implements PlantFactory {
  Plant makePlant() {
    return new Apple();
  }

  Picker makePicker() {
    return new ApplePicker();
  }
}

public class OrangeFactory implements PlantFactory {
  Plant makePlant() {
    return new Orange();
  }

  Picker makePicker() {
    return new OrangePicker();
  }
}

以下图片来自Vaskaran Sarcar的《c#设计模式》第二版:

1. 简单工厂模式

创建对象而不向客户端公开实例化逻辑。

SimpleFactory simpleFactory = new SimpleFactory();
IAnimal dog = simpleFactory.CreateDog(); // Create dog
IAnimal tiger = simpleFactory.CreateTiger(); // Create tiger

2. 工厂方法模式

定义一个用于创建对象的接口,但是让子类来决定实例化哪个类。

AnimalFactory dogFactory = new DogFactory(); 
IAnimal dog = dogFactory.CreateAnimal(); // Create dog

AnimalFactory tigerFactory = new TigerFactory();
IAnimal tiger = tigerFactory.CreateAnimal(); // Create tiger

3.抽象工厂模式(工厂中的工厂)

抽象工厂提供了创建一系列相关对象的接口,而无需显式地指定它们的类

IAnimalFactory petAnimalFactory = FactoryProvider.GetAnimalFactory("pet");
IDog dog = petAnimalFactory.GetDog(); // Create pet dog
ITiger tiger = petAnimalFactory.GetTiger();  // Create pet tiger

IAnimalFactory wildAnimalFactory = FactoryProvider.GetAnimalFactory("wild");
IDog dog = wildAnimalFactory .GetDog(); // Create wild dog
ITiger tiger = wildAnimalFactory .GetTiger();  // Create wild tiger

没有一个答案能真正很好地解释抽象工厂——可能是因为这个概念是抽象的,而且在实践中使用较少。

考虑以下情况,可以举一个容易理解的例子。

你有一个系统,它与另一个系统相连接。我将使用Shalloway和Trott在《设计模式解释》(P194)中给出的例子,因为这种情况非常罕见,我想不出更好的例子了。在他们的书中,他们给出了本地硬件资源的不同组合的例子。他们举例说:

系统具有高分辨率显示和打印驱动程序 系统具有低分辨率显示和打印驱动程序

一个变量有两个选项(打印驱动程序、显示驱动程序),另一个变量有两个选项(高分辨率、低分辨率)。我们希望以这样一种方式将它们耦合在一起,即我们有一个HighResolutionFactory和一个LowResolutionFactory,它们为我们生成正确类型的打印驱动程序和显示驱动程序。

这就是抽象工厂模式:

class ResourceFactory
{
    virtual AbstractPrintDriver getPrintDriver() = 0;

    virtual AbstractDisplayDriver getDisplayDriver() = 0;
};

class LowResFactory : public ResourceFactory
{
    AbstractPrintDriver getPrintDriver() override
    {
        return LowResPrintDriver;
    }

    AbstractDisplayDriver getDisplayDriver() override
    {
        return LowResDisplayDriver;
    }
};

class HighResFactory : public ResourceFactory
{
    AbstractPrintDriver getPrintDriver() override
    {
        return HighResPrintDriver;
    }

    AbstractDisplayDriver getDisplayDriver() override
    {
        return HighResDisplayDriver;
    }
};

我不会详细说明打印驱动程序和显示驱动程序的层次结构,只需要一个就足够演示了。

class AbstractDisplayDriver
{
    virtual void draw() = 0;
};

class HighResDisplayDriver : public AbstractDisplayDriver
{
    void draw() override
    {
        // do hardware accelerated high res drawing
    }
};

class LowResDisplayDriver : public AbstractDisplayDriver
{
    void draw() override
    {
        // do software drawing, low resolution
    }
};

为什么有效:

我们可以用一堆if语句来解决这个问题:

const resource_type = LOW_RESOLUTION;

if(resource_type == LOW_RESOLUTION)
{
    drawLowResolution();
    printLowResolution();
}
else if(resource_type == HIGH_RESOLUTION)
{
    drawHighResolution();
    printHighResolution();
}

现在我们可以这样做:

    auto factory = HighResFactory;
    auto printDriver = factory.getPrintDriver();
    printDriver.print();
    auto displayDriver = factory.getDisplayDriver();
    displayDriver.draw();

本质上——我们已经将运行时逻辑抽象到类的v-table中。

我对这种模式的看法是,它实际上并不是很有用。它把一些不需要结合的东西结合在一起。设计模式的重点通常是减少耦合,而不是增加耦合,因此在某些方面,此模式实际上是反模式,但在某些上下文中可能有用。

如果您到了认真考虑实现此功能的阶段,您可能会考虑一些替代设计。也许你可以编写一个返回工厂的工厂,工厂本身返回你最终想要的对象。我认为这将更加灵活,并且不会有相同的耦合问题。

附录:“四人帮”的例子也有类似的耦合。他们有一个MotifFactory和一个PMFactory。然后分别生成PMWindow, PMScrollBar和MotifWindow, MotifScrollBar。这是一个有点过时的文本,所以它可能很难理解上下文。我记得我读过这一章,从这个例子中除了有两个工厂基类的实现之外,我几乎没有理解什么,它们返回不同的对象族。