Сторонняя обертка API в Java: как создавать - PullRequest
1 голос
/ 13 марта 2019

Предположим, есть сайт, который предоставляет API, такой как:

  • Пользователи размещают вопросы, ответы на этом сайте
  • Вы можете сделать GET и POSTзвонки
  • Существует два типа аутентификации: слабая (только дает права на чтение) и сильная (дает права как на чтение, так и на запись)
  • ПравоТеперь я хотел бы прочитать вопросы и ответы пользователей (нужен только слабый доступ) и отправлять им сообщения или публиковать свои собственные вопросы в будущем (потребуется сильный доступ)
  • 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 I оба return AccessToken и установить Wrapper поле accessToken до результата.Это правильный подход?Или метод only должен возвращать токен доступа, и тогда этот результат должен быть явно назначен полю класса?То же самое относится к методам getQuestions и getAnswers: они оба получают ArrayList s, возвращают их и присваивают поле 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();

Конструктор User будет принимать как имя пользователя, так и данные аутентификации, получать токен доступа и сохранять еговнутри пользователя, а затем использовать его при получении вопросов / ответов или отправки сообщений.Я мог бы сделать поле accessToken внутри User class static, чтобы все пользователи использовали один и тот же токен.

Однако существуют действия, которые предоставляет API сайта, которые явно не связаны с пользователями: например, получение наиболее популярных вопросов сайта.Для этой цели кажется правильным использовать общий класс Wrapper, что противоречит предыдущему подходу.

Я новичок в этом и знаю только пару шаблонов проектирования.Возможно, есть широко распространенные модели, которые должны использоваться для этого типа проблемы?Любая помощь / совет приветствуется.

1 Ответ

1 голос
/ 13 марта 2019

Есть несколько альтернатив, которые вы можете сделать, чтобы решить свою проблему, но, скорее всего, нет одного , который лучше всех остальных.Решение, которое вы выберете, будет зависеть от компромиссов и того, как вы хотите, чтобы ваша система работала.Ниже приведены два распространенных решения проблемы этого типа.

  1. Пусть Wrapper сгенерирует User: вместо создания отдельного объекта Userиз Wrapper можно Wrapper сгенерировать объект User.Это позволяет Wrapper встраивать AccessToken в User без какого-либо внешнего клиента, который знает, что у пользователя есть AccessToken.Например, вы можете использовать следующие определения 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;
    
        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.

  2. Вставить Wrapper в User: Этот метод похож на (1), но он также внедряет объект Wrapper в объект User.Это позволяет классу 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.Обратите внимание, что методы findQuestions и findAnswers начинаются с find.Это предупреждает клиентов о том, что этот вызов может быть длинным (в отличие от getQuestions или getAnswers, что заставит клиента предположить, что это простой метод получения и метод будет возвращаться почти мгновенно).Тот факт, что эти методы выполняют удаленный вызов, также должен быть документирован в документации Java для методов.Если вызов занимает много времени, методы должны возвращать 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.Это призыв к суждению, который будет зависеть от характера вашего конкретного приложения.

Существует множество других методов, которые вы можете использовать, но вышеупомянутые два являются общими подходами к проблеме, с которой вы сталкиваетесь.пытаясь решить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...