如何强制API Java的实现

时间:2018-01-05 09:04:24

标签: java interface abstract api-design

我们在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?请帮助似乎无法想出这一个

4 个答案:

答案 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.
    }
}
  1. 在MyReader的默认构造函数中,您必须使用Authroized的实例,例如new Authorized("").super()
  2. 您无法继承Authroized来重写构造函数。
  3. 如果没有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");
    }
}