我在工厂实施了一个负责管理应用程序令牌的类。我将在这个简化的例子之后解释我面临的问题:
假设我们有工厂类:
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
现在我们在main {
TokenManager tm = TokenManagerFactory.create("JWT");
tm.aMethodNotDefinedInInterface(); // <-- Compilation error.
}
中想要创建一个JwtTokenManager实例:
{{1}}
未定义类型的方法aMethodNotDefinedInInterface() TokenManager
如何调整此设计模式以避免发生此错误?进行此类调用时的向下转换似乎是一个苛刻的解决方案,我是否可以通过更高级别的调整来适应这种情况?
感谢。
我标记了我最终使用的解决方案。
答案 0 :(得分:2)
如何调整此设计模式,以免发生此错误?
您必须做出选择:使用基本公共类型从基本公共类型的API以统一的方式操作所有子类,或者将其转换为特定类型以便能够调用子类的特定方法。
解决问题的一些想法:
在界面中添加方法
如果某些实现需要该方法但不是所有实现,则可以在接口中添加默认实现(例如抛出UnsupportedOperationException
)。您可以在想要支持它的子类中覆盖它
它会起作用,但也会使你的代码变得更脆弱,因为异常仅在运行时抛出。
提供一个额外的工厂方法,在其声明中返回具体的子类。
或者作为替代方法,丰富实际方法以返回由调用者返回中指定的目标类型推断的泛型类型。它不是类型安全的,但它可以保留一个明确的演员阵容。
它会给出类似的东西:
@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"));
答案 1 :(得分:1)
您可以更改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();
}
答案 2 :(得分:1)
如果所有令牌管理员都需要aMethodNotDefinedInInterface()
,则应将其添加到界面中。
否则,这表明每个令牌管理器需要不同的流,在这种情况下,您可能希望使用Bridge设计模式。
在这种情况下, Implementor 层次结构将成为令牌管理器,抽象层次结构将包含不同的流程实现。
然后,您可以将所需的流与所需的令牌实现相匹配。
您仍然需要将该方法添加到界面中,并且:
UnsupportedOperationException
异常,表示流/令牌管理器组合是非法的。答案 3 :(得分:0)
我将首先谈谈你的设计有什么问题:
这是你的代码:
TokenManager tm = TokenManagerFactory.create("JWT");
tm.aMethodNotDefinedInInterface(); // <-- Compilation error.
问题是,为什么当您只有一个可能的值时,create方法会获取一个令牌?你也可以总是返回具体的类型。
你要告诉我你可能想要这样做:
String token = getTokenFromSomewhere(); // it may or may not be JWT
TokenManager tm = TokenManagerFactory.create(token);
tm.aMethodNotDefinedInInterface(); // <-- Compilation error.
在这种情况下,你不知道你返回了什么类型的TokenManager
,所以你不能在它上面调用一个方法,除非它在界面中。
您现在可能会说您想要执行这两种情况中的任何一种情况 - 使用已知令牌或未知令牌。在这种情况下,已知的令牌情况有点误用工厂方法,因为它的设计是返回任何类型的令牌。您以两种不同的方式使用工厂。因此,您可以为特定令牌创建特定的工厂方法,或者只使用强制转换。
答案 4 :(得分:0)
接口中未定义的方法无法使用接口类型调用。因此,在调用特定方法(不在接口中,但在特定类中)之前,必须将接口类型TokenManager的引用变量tm强制转换为其中一个子类型。
setStyle