Java中的第三方API包装器:如何设计

时间:2019-03-12 22:29:10

标签: java api oop design-patterns

假设有一个提供API的网站,例如:

  • 用户在该网站上发布问题和答案
  • 您可以制作GETPOST个呼叫
  • 有两种身份验证类型:(仅提供 读取权限)和 strong (同时赋予读取和写入权限)
  • 现在,我想阅读用户的问题和答案(只需要弱访问权限),然后向他们发送消息或发表我自己的问题(需要强访问权限)
  • 该网站的API具有与用户(例如发送消息)和整个网站(请参阅有关,请参阅最常见的问题)的两者操作

我现在拥有的东西看起来像这样:

public class Wrapper  {
   private AccessToken accessToken;

   public Wrapper(...)  {
     //does some stuff
     //gets access token:
     getAccessToken(...);
   }    

   public AccessToken getAccessToken(...)  {
      AccessToken result;
      //gets access token, given the auth info provided as arguments
      accessToken = result;

      return result; 
   }

   public ArrayList<Question> getQuestions(User user)  {
       //gets user's questions, using the accessToken field
       //set's a user's questions field to the result and returns the result
   }

   public ArrayList<Answer> getAnswers(User user)  {
       //same as previous
   }

   public boolean sendMessage(User user)  {
      //sends a message, if current accessToken is strong
   }
}

用户类:

class User  {
  private String username;

  private ArrayList<Question> questions;
  private ArrayList<Answer> answers;

  public User(String username) {this.username=username;}    

  //getters and setters
}

因此,要使用它,您将使用类似以下的内容:

public class Main  {
  public static void main(String[] args)  {
     Wrapper wrapper = new Wrapper(...);
     ArrayList<Question> questions = wrapper.getQuestions(new User("username"));
     wrapper.sendMessage(new User("username2"));
  }
}

我对此有疑问。

首先,类User感到多余,因为所有功能都在Wrapper类内部。

第二,我想知道我的方法是否正确-从设计的角度来看:在getAccessToken中,我返回AccessToken 结果的Wrapper字段accessToken。这是正确的方法吗?还是应该 only 方法返回访问令牌,然后将结果明确分配给类的字段? getQuestionsgetAnswers方法也一样:它们两者都得到ArrayList,返回它们并分配一个{{1 }}的结果字段-都在单个方法内。

我希望User类具有一定的意义。我想做这样的事情:

User

因此, Wrapper wrapper = new Wrapper(...); User user = new User("username"); user.getQuestions(wrapper.getAccessToken()); user.sendMessage(wrapper.getAccessToken()); 类仅用作从中获取访问令牌的地方,感觉也不好。我可以将访问令牌功能放在Wrapper类中,并像这样使用它:

User

User user = new User("username", ...); user.getQuestions(); user.sendMessage(); 的构造函数将同时使用用户名和身份验证数据,将获取访问令牌并将其存储在用户内部,然后在获取问题/答案或发送消息时使用它。我可以在UseraccessToken中创建User字段,以便所有用户共享相同的令牌。

但是,网站API提供了一些显然与用户无关的操作:例如,获取网站最受欢迎的问题。为此目的使用通用的static类是正确的,这与以前的方法相矛盾。

我对此并不陌生,只知道几种设计模式。也许,有广泛的模式可用于此类问题?任何帮助/建议,表示赞赏。

1 个答案:

答案 0 :(得分:1)

您可以采取几种替代方法来解决问题,但是一个可能没有一个比其他所有方法都好。您选择的解决方案将取决于权衡以及您希望系统如何运行。以下是针对此类问题的两种常见解决方案。

  1. Wrapper生成一个User :您可以将UserWrapper分开生成Wrapper对象User生成Wrapper对象。这使AccessToken可以将User嵌入AccessToken内,而没有任何外部客户端知道用户拥有Wrapper。例如,您可以使用以下Userpublic class Wrapper { public Wrapper(...) { // ... does some stuff, but DOES NOT get an access token ... } private AccessToken getAccessToken(...) { AccessToken result; // ... gets access token, given the auth info provided as arguments ... return result; } public User findUser(String username, ...) { return new User(username, getAccessToken(...)); } } class User { private String username; private final AccessToken token; public User(String username, AccessToken token) { this.user = user; this.token = token; } // ... getters and setters ... } 定义:

    getAccessToken

    请注意,private现在是Wrapper,因为没有其他客户端需要访问此方法。 User的所有方法都继续接受getToken参数,但是现在它们应该通过在User对象上调用AccessToken而不是使用存储的方法来获取访问令牌。 Wrapper中的token

    还请注意,final字段为User,因为与User关联的访问令牌在Wrapper对象的生命周期内不应更改。

  2. User嵌入Wrapper :此技术类似于(1),但它也将User对象嵌入{ {1}}对象。这使User类可以充当活动对象,可以向其查询问题和答案,并可以用于发送消息。由于Wrapper的所有方法都接受User自变量,因此这是将方法移至User的好兆头。以下是将Wrapper方法重构为User的过程:

    public class Wrapper  {
    
       public Wrapper(...)  {
           // ... does some stuff, but DOES NOT get an access token ...
       }    
    
       private AccessToken getAccessToken(...)  {
           AccessToken result;
           // ... gets access token, given the auth info provided as arguments ...
           return result; 
       }
    
        public User findUser(String username, ...) {
            return new User(username, getAccessToken(...));
        }
    
        public ArrayList<Question> getQuestions(User user)  {
            //gets user's questions, using the accessToken field
            //set's a user's questions field to the result and returns the result
        }
    
        public ArrayList<Answer> getAnswers(User user)  {
            //same as previous
        }
    
        public boolean sendMessage(User user)  {
            //sends a message, if current accessToken is strong
        }
    }
    
    class User  {
    
        private String username;
        private final AccessToken token;
        private final Wrapper wrapper;
    
        public User(String username, AccessToken token, Wrapper wrapper) {
            this.user = user;
            this.token = token;
            this.wrapper = wrapper;
        }
    
        public List<Question> findQuestions() {
            return wrapper.getQuestions(this);
        }
    
        public ArrayList<Answer> findAnswers()  {
            return wrapper.getAnswers(this);
        }
    
        public boolean sendMessage()  {
            return wrapper.sendMessage(this);
        }
    
        // ... getters and setters ...
    }
    

    使用此技术,客户现在可以直接从User对象获得问题和答案。请注意,findQuestionsfindAnswers方法以find开头。这提示客户端此调用可能是长调用(与getQuestionsgetAnswers相对,这会使客户端假定这是一个简单的getter,并且该方法几乎立即返回)。这些方法执行远程调用的事实也应在Java-docs中记录这些方法。如果调用需要很长时间,则方法应返回Future(或类似的对象)并异步进行。

    如果要全力参与重构,可以将所有实现细节从Wrapper类移动到User类:

    public class Wrapper  {
    
       public Wrapper(...)  {
           // ... does some stuff, but DOES NOT get an access token ...
       }    
    
       private AccessToken getAccessToken(...)  {
           AccessToken result;
           // ... gets access token, given the auth info provided as arguments ...
           return result; 
       }
    
        public User findUser(String username, ...) {
            return new User(username, getAccessToken(...));
        }
    }
    
    class User  {
    
        private String username;
        private final AccessToken token;
        private final Wrapper wrapper;
    
        public User(String username, AccessToken token, Wrapper wrapper) {
            this.user = user;
            this.token = token;
            this.wrapper = wrapper;
        }
    
        public List<Question> findQuestions() {
            // ... find the questions remotely ...
        }
    
        public ArrayList<Answer> findAnswers()  {
            // ... find the answers remotely ...
        }
    
        public boolean sendMessage()  {
            // ... send message remotely ...
        }
    
        // ... getters and setters ...
    }
    

    这可能不是最好的方法,因为将访问远程API的详细信息保留在Wrapper类中可能是一个更好的主意。这是一个判断调用,将取决于您特定应用程序的性质。

您还可以使用许多其他方法,但是以上两种是解决您要解决的问题的常用方法。