PHP OOP :: Создание класса API Wrapper - PullRequest
11 голосов
/ 08 января 2011

У меня есть приложение, которое по сути является оберткой для стороннего API.Приложение не использует базу данных и хранит только один файл cookie, который является идентификатором сеанса, который требуется API.

API представляет собой систему покупок, которая позволяет пользователям

-login / register /изменить профиль / выйти из системы

- купить товар

- сделать пожертвование

- стать участником

API имеет около 50 методов, которые нужны моему приложениюподключиться к.Примерами API-вызовов являются addItemToBasket (), addDonation (), GetUserDetails () и т. Д.

Я пытаюсь выяснить, какими должны быть классы в моем приложении.Вот что у меня есть:

Классы

1) APIManager () Класс Содержит методы, которые соответствуют один к одному сметоды, представленные в стороннем API и обеспечивающие механизм подключения к удаленному API-серверу.Таким образом, пользователь будет авторизован через

APIManager->loginUser($sessionKey, $uid, $pwd);

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

 APIManager->isLoggedIn($sessionKey);

2) User () Class Содержит методы, содержащие бизнес-логику, необходимую перед обработкой вызовов API, таких как Register или Login.Пример метода:

function login($_POST) {
    //perform sanity checks, apply business rules etc.
    //if certain conditions are met, we may pass in a promo code, $pc

    APIManager->loginUser($sessionkey, $_POST['uid'], $_POST['pwd'], $pc);
}

Я понимаю, что, возможно, я мог бы просто сделать вызов APIManager со страницы входа в систему, а не иметь пользовательский класс как таковой, но я чувствовал, что, поскольку некоторая бизнес-логика должназапустить до того, как мы на самом деле вызовем метод API loginUser (), было бы правильно, чтобы это обрабатывалось в классе User.Мне было бы интересно узнать, что люди думают об этом.

3) Basket () Класс

Корзина управляется в стороннем API, поэтому мое приложениероль состоит в том, чтобы делать соответствующие вызовы API, чтобы добавлять новые элементы в корзину, удалять элементы, просматривать корзину и т. д. Мое приложение ничего не знает о корзине до тех пор, пока данные не будут получены из API, и при этом оно не может вносить какие-либо изменения в корзину безидет через API.Опять же, было целесообразно сгруппировать эту связанную логику в класс Basket.Веб-страница интерфейса может вызывать что-то вроде:

Basket->addItem(23);

, и этот метод addItem () в классе Basket будет выглядеть примерно так:

addItem($itemID) {
   //perform checks, apply business rules e.g. if user is eligible for discount
        APIManager->addToCart($itemID, $discount);
}

, где addToCart () является третьимМетод партийного API, который мы вызываем для обработки элемента.

4) Donation () Класс

Это позволяет пользователям делать пожертвования.Пожертвование появляется в корзине и может быть удалено из корзины.Я думал просто добавить метод addDonate () в класс Basket и не беспокоиться о наличии объекта Donation, но ... (см. Ниже)

5) Membership () Класс

... членство на самом деле является своего рода пожертвованием!API будет рассматривать пожертвование, поступающее на определенный счет, как членство на 1 год, а не как обычное пожертвование.Мы не можем изменить логику / поведение стороннего API.

Итак, если я пожертвую 50 долларов на счет «1», то это просто обычное пожертвование, но если я пожертвую 100 долларов на счет «8», я станучлен со всеми преимуществами участника (сниженные цены, отсутствие почтовых сборов и т. д.).

Здесь я не уверен, как лучше спроектировать это.

Должен ли я создать класс для пожертвованийи затем продлите это с помощью членства, так как все методы пожертвования потребуются членством.Но для членства потребуются дополнительные методы, такие как renew () или getExpiry () и т. Д.

Кроме того, я должен смотреть на расширение пользователя, чтобы стать членом?Опять же, у члена есть все основные методы, которые есть у пользователя, но есть и дополнительные, такие как getSpecialOffers () или getDiscountCode (), к которым будут иметь доступ только члены.

Любое руководство по наилучшему подходу к дизайнуБуду очень признателен.

Спасибо, Джеймс

Ответы [ 2 ]

22 голосов
/ 02 февраля 2011

Лично я бы построил это в 3 слоя.

Уровень 1: Интерфейс API

Этот уровень - то, где фактические вызовы на уровне линии обращаются к удаленному APIпроисходить.Этот уровень все о протоколе.В этом слое не должно быть ничего, специфичного для API.Все должно быть на 100% общим, но должно быть в состоянии использоваться средним уровнем для взаимодействия с API.Обратите внимание, что этот слой может быть из библиотеки или другого источника, например, фреймворка.Или вы можете написать это на заказ.Все зависит от того, где вы находитесь и ваши точные потребности.

Некоторые классы, которые могут здесь принадлежать:

  • XMLRPC_Client
  • SOAP_Client
  • REST_Client

Уровень 2: Адаптер API

Этот слой фактически содержит информацию API, жестко запрограммированную в нем.В основном это шаблон адаптера .По сути, работа этого уровня заключается в преобразовании удаленного API в локальный API с использованием уровня Interface.Таким образом, в зависимости от ваших потребностей, вы можете зеркально отразить удаленный API в виде 1: 1, или вы можете отогнать его под свои нужды.Но следует помнить, что этот класс не предназначен для обеспечения функциональности вашей программы.Цель состоит в том, чтобы отделить удаленный API от вашего локального кода.Поменяв этот класс, ваш код сможет быстро адаптироваться для использования разных версий удаленного API и, возможно, даже разных удаленных API вместе.

Важно помнить, что этот уровень адаптера предназначен дляохватывать API.Таким образом, область действия каждого отдельного класса - это полная реализация API.Таким образом, должно быть соотношение 1: 1 между адаптерами и удаленными API.

Некоторые классы, которые могут быть здесь:

  • RemoteAPI_v1_5
  • RemoteAPI2_v1

Уровень 3: Внутренние объекты

Этот слой должен быть вашим внутренним представлением различных объектов (в вашем конкретном случае: пользователь, корзина, корзина, пожертвование, членство и т. Д.).Они не должны напрямую вызывать API, а использовать Composition (Dependency Injection), чтобы стать тем, что по сути является мостом для API.Сохраняя его разделенным, вы сможете изменять API полностью независимо от внутренних классов (и наоборот).

Итак, один из ваших классов может выглядеть так:

class User {
    protected $api;
    public function __construct(iAPIAdapter $api) {
        $this->api = $api;
    }
    public function login() {
        $this->api->loginUser($blah);
    }
}

Таким образом, нет никакой необходимости в API manager , так сказать.Просто создайте новый экземпляр API в начале программы и передайте его остальной части кода.Но главное преимущество в том, что он достаточно гибок в том смысле, что вы должны иметь возможность изменять API (либо версию, либо сам вызов), просто заменяя слой адаптера в своем коде (когда вы создаете экземпляр адаптера).Все остальное должно просто работать, и вы должны быть полностью изолированы от изменений в вашем коде или удаленном API (не говоря уже о том, что он должен быть достаточно тестируемым, если построен таким образом) ...

Это мои $ 0,02.Это может быть излишним, но это действительно зависит от вашей потребности ...

0 голосов
/ 01 марта 2011

Я бы сказал:

  1. создайте класс пожертвования со всем необходимым
  2. создайте переменную-членство членства (которая должна иметь тип Donation).*
  3. у вас может быть метод в классе членства, такой как:

    public function makeDonation($data) {
        $this->donation = new Donation($data) // maybe with the data parameter;
        $this->donation->commit() // whatever it does to set things up
          ......
          whatever you need
    }
    

Таким образом, у вас есть хорошая развязка между элементами.Также Donation должен реализовывать интерфейс интерфейса, чтобы при дальнейшем изменении поведения он все равно содержал методы, требуемые классом memeber.

Таким образом, он более гибкий, чем наследование.Я задал похожий вопрос некоторое время назад и получил хороший ответ:

Элегантные альтернативы странному множественному наследованию

...