工厂设计模式——在子类中定义方法

Factory Design Pattern - defining methods in subclasses

我正在实现一个工厂 class 负责管理应用程序中的令牌。我将在这个简化示例之后解释我面临的问题:

假设我们有工厂class:

TokenManagerFactory.java:

public class TokenManagerFactory {

    public static TokenManager create(String tokenType)
    {
        if ("JWT".equals(tokenType))
            return new JwtTokenManagerImpl();

        return null;
    }


}

然后我们的abstract interface:

public abstract interface TokenManager {
    public  String       generateToken();
    public  boolean      verifyToken();
}

最后执行 JwtTokenManagerImpl:

public class JwtTokenManagerImpl implements TokenManager {
    //..Implementation of methods defined in interface (generateToken() and 
    //  verifyToken())

    public String aMethodNotDefinedInInterface() {
        return "A very cool String";
    }
}

现在在我们的 main 中,我们要创建 JwtTokenManager 的实例:

main {

    TokenManager tm = TokenManagerFactory.create("JWT");
    tm.aMethodNotDefinedInInterface(); // <-- Compilation error.

}

The method aMethodNotDefinedInInterface() is undefined for the type TokenManager

如何调整此设计模式,以免发生此错误?在进行此类调用时向下转换似乎是一个苛刻的解决方案,我是否可以进行更高级别的调整以适应这种情况?

谢谢。


我标记了我最终使用的解决方案。

How do I adjust this design pattern so this error does not occur?

您必须做出选择:要么使用基本公共类型以统一方式从基本公共类型的 API 操作所有子类,要么将其转换为特定类型以便能够调用子类的特定方法。

解决您的问题的一些想法:

  • 在界面中添加方法
    如果某些实现需要该方法,但不是所有实现都需要该方法,您可以使用默认实现将其添加到接口中(例如,抛出 UnsupportedOperationException)。您可以在想要支持它的子类中覆盖它。
    它会起作用,但也会使您的代码更脆弱,因为异常只会在运行时抛出。

  • 提供一个额外的工厂方法,return在其声明中作为具体子类。

  • 或者作为替代方案,将实际方法丰富为 return 由调用程序的 return 中指定的目标类型推断的泛型类型。它不是类型安全的,但它避免了显式转换。

它会给出类似的东西:

@SuppressWarnings("unchecked")
public static <T extends TokenManager> T create(String tokenType) {
    if ("JWT".equals(tokenType)) {
        return (T) new JwtTokenManagerImpl();
    }
    return null;
}

您调用:

JwtTokenManagerImpl token = create("JWT");
  • 如果符合您的需要,请使用装饰器模式来丰富某些对象的行为。您应该依赖 TokenManager 中装饰器将丰富的常用方法。
    你可以这样写:

TokenManager tm = new TokenFooDecorator(TokenManagerFactory.create("JWT"));

您可以更改 TokenManagerFactory 以接受接口吗?

public interface JwtTokenManager extends TokenManager {
    String aMethodNotDefinedInInterface();
}

public class TokenManagerFactory {

    public static <T extends TokenManager> T create(Class<T> managerInterface) {
        if (managerInterface == JwtTokenManager.class) {
            return (T) new JwtTokenManagerImpl();
        }

        return null;
    }
}

那么你使用工厂的地方可以是这样的:

public static void main(String[] args) {
    JwtTokenManager tm = TokenManagerFactory.create(JwtTokenManager.class);
    tm.aMethodNotDefinedInInterface();
}

如果所有令牌管理器都需要aMethodNotDefinedInInterface(),则应将其添加到界面中。


否则,这表明您需要为每个令牌管理器使用不同的流程,在这种情况下,您可能需要使用 Bridge 设计模式。

在这种情况下,实施者 层次结构将是令牌管理器,而抽象 层次结构将由不同的流实现组成。
然后您可以将您想要的流程与您想要的令牌实现相匹配。

您仍然需要将方法添加到界面,并且:

  1. 在不相关的地方添加一个空的实现。
  2. 抛出UnsupportedOperationException异常,说明flow/token经理组合不合法

我先说说你的设计有什么问题:

这是您的代码:

TokenManager tm = TokenManagerFactory.create("JWT");
tm.aMethodNotDefinedInInterface(); // <-- Compilation error.

问题是,当您只有一个可能的标记值时,为什么 create 方法采用该标记?您也可以总是 return 具体类型。

你要告诉我你可能想要这样做:

String token = getTokenFromSomewhere(); // it may or may not be JWT
TokenManager tm = TokenManagerFactory.create(token);
tm.aMethodNotDefinedInInterface(); // <-- Compilation error.

在那种情况下,您不知道 return 是什么类型的 TokenManager,因此除非它在接口中,否则您不能调用它的方法。

您现在可能会说您想要执行这两种情况中的任何一种 - 使用已知令牌或未知令牌。在这种情况下,已知的令牌情况有点误用工厂方法,因为它的设计是 return 任何类型的令牌。您以两种不同的方式使用工厂。因此,您可以为特定令牌创建特定的工厂方法,或者只使用强制转换。

接口中未定义的方法无法使用接口类型调用。因此,在调用特定方法之前,必须将接口类型 TokenManager 的引用变量 tm 转换为子类型之一(即不在接口中,而是在特定的 class)。

if (tm instanceof JwtTokenManagerImpl ) {
  JwtTokenManagerImpl  jwtTm = (JwtTokenManagerImpl) tm;
  jwtTm.aMethodNotDefinedInInterface();
}