Factory方法更适合图书馆的框架和抽象工具吗?

时间:2017-02-28 19:03:29

标签: java oop design-patterns abstract-factory factory-method

抽象工厂和工厂方法模式都是创建设计模式,它解决了不同场景下的对象创建问题。

根据GOF 工厂方法模式

  

定义用于创建对象的接口,但让子类决定实例化哪个类。 Factory方法允许类将实例化延迟到子类。

我的理解: 客户端的动机是获取基本工厂类中的方法得到执行,这取决于现在不知道具体类的对象(在这种情况下,在向客户提供软件期间) ,它将被定义,或者它将是客户自己编写的具体实现,最有可能是框架)。未知(或可能更改)的产品提供了一种抽象类型:IProduct,并设置了一个合同,以后,任何产品实现都必须实现此接口。

IProduct界面

package com.companyx;
public interface IProduct {
    public void serve();
}

使用'方法'需要执行

package com.companyx;
public abstract class Factory {
    public abstract IProduct createProduct();
    private void performCriticalJob(){
        IProduct product = createProduct();
        product.serve();
    }
    public void executeJob(){
        //some code
        performCriticalJob();
        //some more code
    }
}

一些具体产品

package com.companyx;
class AppAProductFeatureX implements IProduct{
    @Override
    public void serve() {
        //some code
    }
}

具体产品的工厂

package com.companyx;
public class AppAFeatureXProductFactory extends Factory{
    @Override
    public IProduct createProduct() {
        return new AppAProductFeatureX();
    }
}

客户代码

package com.clientcompany;
import com.companyx.AppAFeatureXProductFactory;
import com.companyx.Factory;
public class Client {
    public static void main(String[] args) {
        Factory fact = new AppAFeatureXProductFactory();
        fact.executeJob();
    }
}

根据GOF 抽象工厂模式

  

提供用于创建相关或从属对象族的接口,而无需指定其具体类。

我的理解 客户对产品感兴趣,此模式通过隐藏工厂类后面的具体产品类来帮助提供产品。

客户需要的产品类型

package com.companyb;
public interface IProductA {
    public void performAJob();
}

产品的实施

package com.companyb;
//can be named better, but lets go with this name for this time
public class ProductAVersion1 implements IProductA{
    @Override
    public void performAJob() {
        // some code
    }
}

工厂界面,(它也可以是抽象类)

package com.companyb;
public interface IFactory {
    public IProductA createProduct();
}

Factory的具体实现o创建ProductA

package com.companyb;

public class FactoryA implements IFactory{
    @Override
    public IProductA createProduct() {
        return new ProductAVersion1(); // concrete class of product is hidden
    }
}

客户代码

package com.clientcompany.productprovider;
import com.companyb.IFactory;
import com.companyb.IProductA;
public class SomeClientClass {
    private IFactory factory;
    private IProductA product;

    public void doSomeJobWithProductA() {
        // some code
        product.performAJob();
        //someCode();
    }
    public void setFactory(IFactory factory) {
        this.factory = factory;
        this.product = factory.createProduct();
    }
}

package com.clientcompany.productprovider;
import com.companyb.FactoryA;
public class SomeOtherClientCode {
    public static void main(String[] args) {
        SomeClientClass someClientClass = new SomeClientClass();
        someClientClass.setFactory(new FactoryA());
        someClientClass.doSomeJobWithProductA();
    }
}

Q1 :抽象工厂模式中是否需要相关产品系列,如果只有一种产品(如上所述)有各种子类型,那么这种模式仍然是相关的但不是各种相关类型?

Q2 我的理解是否正确?

Q3 上面给我带来了另一个疑问:Factory方法更适合框架(客户端可以提供产品的实现),就像模板方法模式一样,工厂调用{{1}具体实现从用户提供的Concrete Factory实现? 同样,抽象工厂更适合图书馆开发,具体的产品类别(可能会有所不同)隐藏在更稳定的工厂类别背后?

3 个答案:

答案 0 :(得分:1)

根据我的理解:

A1 :产品系列不一定必须相关,如example diagram所示,只需要了解产品类型的客户。这种关系大多是自然的,因为你可能不希望同一个客户创建2个不相关的对象,例如,如果你有一个" AbstractPizzaFactory"它会看起来很奇怪。创造比萨饼和汽车,没有?

A2 :从技术上讲,您可以在Factory模式中提供默认的工厂方法,这样您仍然可以创建(默认)新对象,而无需始终对其进行子类化。

A3 :我同意你的观点,尽管创建图书馆或框架绝不是黑白分明。

答案 1 :(得分:1)

我很难穿上你的鞋子。但我对这个问题很感兴趣,所以我会试一试。这里涉及的概念包括libraryframeworkfactory methodabstract factoryproduct family等。

首先,library vs framework与工厂,抽象工厂或任何模式无关。图书馆与框架的争论不是从模式发挥作用的实现角度出发的。例如,JUnit是一个带有丰富断言库的框架。那么,对于内部实现,junit是否应该优先选择其他模式? Java本身是一个带有JCL库的框架。 Dot Net与java类似,甚至称自己为框架,并包含BCL库。因此,在实施环境中没有更多的框架与图书馆辩论。

所以问题归结为你应该使用哪种模式?它不是关于差异,这是明确的,而是关于在哪种场景中使用哪一个。在此上下文中,Client Code是您正在键入的call所有代码。一些代码是由您或其他人在相同或不同的jar中,来自相同或不同的组织编写并不重要。从一个代码片段的角度来看,任何其他代码(即使在同一个类的不同方法中)是客户端代码,如果该代码有可能call你正在输入的代码。

在键入任何代码(无论框架或库状态)时,有时我们需要获取某些对象的实例。我们可能需要一个BufferedReader。如果在编译时我们绝对确定对象的具体类,KISS它并与new一起使用。

我们可能不知道实例的具体类。现在质疑客户端代码是否有此信息?如果客户端代码知道实际的具体类,但我不知道,那么我们使用FactoryMethod模式。我输入的代码将在(例如)其参数列表中询问工厂对象的实例。知道实际具体类的客户端代码将提供将进行创建的工厂对象。在JDBC中可以看到这种情况的示例,就像我们要处理sql语句一样。在编译时,我们不知道是否应该实例化mysql.JDBC4PreparedStatementmicrosoft.SQLServerStatement。它取决于连接字符串,这取决于最终用户。因此,我们抓住Connection个实例并将其提交给createStatement()。请参阅,我们将sql.Statement类型的对象的构造委托给sql.Connection的子类。这里conn实例是工厂对象。我们如何掌握工厂是无关紧要的,只是我们从客户代码获得它。

如果我们需要一个Process对象的实例,并且在编译时我们不知道它是Win32Process还是UnixProcess,我们将其创建的责任委托给与工厂模式相关的ProcessBuilder builder pattern。同样适用于jdbc ConnectionManager

如果有很多不同的类通过继承而不是家庭相关,我们可能会使用AbstractFactory。例如,取jdbc的点网对应DbProviderFactory。我的代码需要ConnectionCommandDataReader等实例,这些实例与继承无关,而是与MySql或SqlServer的 family 相关。所以我们得到了DbProviderFactory的子类的实例。可能是MySqlProviderFactorySqlProviderFactory取决于运行时和客户端代码。一旦我们拥有该工厂,我们就可以CreateCommand()CreateConnection()等。

希望这有助于您在工厂模式和抽象工厂模式之间进行选择。

答案 2 :(得分:0)

抽象工厂可以看作是工厂方法的集合。

为了更好地理解现实生活中的例子,可以提供帮助:
Factory Method - 橡皮泥/模具
Abstract Factory - 卡片工厂