工厂设计模式——在子类中定义方法
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 设计模式。
在这种情况下,实施者 层次结构将是令牌管理器,而抽象 层次结构将由不同的流实现组成。
然后您可以将您想要的流程与您想要的令牌实现相匹配。
您仍然需要将方法添加到界面,并且:
- 在不相关的地方添加一个空的实现。
- 抛出
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();
}
我正在实现一个工厂 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 设计模式。
在这种情况下,实施者 层次结构将是令牌管理器,而抽象 层次结构将由不同的流实现组成。
然后您可以将您想要的流程与您想要的令牌实现相匹配。
您仍然需要将方法添加到界面,并且:
- 在不相关的地方添加一个空的实现。
- 抛出
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();
}