我们在API设计上有这个问题。它在我的头上钻了一个洞,无法想出这个。
比如说我有一个接口有一个方法,要读取文件但你需要传递一些凭证,所以这里的对象可能是任何pojo。
public interface Reader(){
public void read(String identifier, Object credentials);
}
问题是我如何强制开发人员扩展它以实现凭据,以确保它是有效的凭据而不是绕过它。以下是我建议的解决方案:
public boolean authenticate(Object credentials);
或者,它可能是这样的
public Object authenticate(Object credentials);
我也尝试过这种方式,因此它提供了默认身份验证
public interface Auth {
default boolean authenticate() {
//do real authentication
return true;
}
}
以及我将传递给Reader
界面的回复,他们回到我身边说开发人员也可以一直忽略这一点,只说return true
。所有这一切都是错误的。
他们暗示答案与Abstract classes
有关,但我在想它是否是一个抽象类,是不是意味着如果我扩展并不意味着我仍然可以覆盖这种方法?并说return true
仍然?
abstract class Auth {
public boolean authenticate(Object o) {
//some real authentication
return boolean ;
}
}
//developer implementation
class extends AuthImpl extends Auth{
public boolean authenticate(Object o){
return true;
}
}
这是一个小组讨论,他们都同意有一种方式,以便开发人员不能只使用摘要返回true。我在这里错过了什么?如何强制开发人员正确实现实际身份验证而不是仅返回true?请帮助似乎无法想出这一个
答案 0 :(得分:2)
如果你想强制执行,你必须有一个类,抽象或不抽象。当然authenticate
会被final
所以它不能被覆盖(当然,如果你是开发人员,没有什么可以阻止你让它成为非最终的,所以它会变得有点学术如何真正确保安全。)
一种方法是从外部将Reader实现作为参数,因此开发人员可以自由地实现读取,但系统的其余部分始终使用AuthReader
(这会产生直接依赖性)对于更难绕过的身份验证,因为它需要更改所有使用它的所有地方)。这样可以灵活地进行阅读,但在身份验证方面具有安全性。
像这样的东西
public final class AuthReader implements Reader {
private Reader reader;
private Object credentials;
public AuthReader(Reader reader, Object credentials) {
this.reader = reader;
this.credentials = Objects.requireNonNull(credentials);
}
private boolean isAuthenticated() {
... // authenticate credentials
}
public String readString() {
if(!isAuthenticated())
throw new SecurityException();
return reader.readString();
}
}
答案 1 :(得分:0)
我认为他们希望看到以下合同模式:
public abstract class Reader(){
// Requirement to implement:
protected abstract void authenticate(Object credentials);
// Requirement to implement:
protected abstract void actuallyRead(BufferedReader in, String identifier,
Object credentials) throws IOException;
// Service provided:
public final void read(String identifier, Object credentials) {
... using authenticate and actuallyRead ...
}
}
客户端开发人员只有一个read
函数的API。但实现者必须提供功能(authenticate, actuallyRead
)。它用作 API创建者指定。
请注意,actuallyRead
可以传递(提供)并返回(需要)额外信息。
答案 2 :(得分:0)
让我们假设您只允许使用有效凭据即时创建授权实例。
假设你有这个:
public final class Authorized {
private final Object credentials;
public abstract class Reader {
}
public Authorized(Object credentials) {
if (credentials == null) {
Objects.requireNonNull(credentials, "Missing credentials");
}
this.credentials = credentials;
}
}
通过这种方式,您可以从Reader进行扩展,但是您无法通过Reader 快速显示超类,而的实例为Authorized
。
示例:
public class MyReader extends Authorized.Reader {
public MyReader() {
// YOU MUST CALL .super() HERE ON A
// INSTANCE OF Authroized or you can not compile.
}
}
new Authorized("").super()
。Authroized
来重写构造函数。Authroized
的实例,则无法创建MyReader的实例。答案 3 :(得分:0)
在给出一些想法并基于这里的所有答案之后,我认为这就是他们的意思。感谢@ Kayaman给出正确方向的答案。
通过abstract
这就是方法,因为你强加了Reader
有1个参数constructor
他无法实例化它,并且他被迫进行super
调用在他的实施中。
abstract class Reader {
protected Object authentication;
ReaderImpl(Object authentication) throws Exception{
if(null == authentication){
throw new Exception();
}else{
this.authentication = authentication;
}
}
public void reader(String x, Object authentication) {
System.out.println("Reader Implemented");
}
}
class DevReader extends Reader{
public DevReader(Object authentication) throws Exception{
super(authentication);
}
@Override
public void reader(String x, Object authentication) {
System.out.println("Dev Implemented");
}
}