#ruby-on-rails #ruby #api #design-patterns
#ruby-on-rails #ruby #API #шаблоны проектирования
Вопрос:
Я заинтересован в написании библиотеки для стороннего API, который я использую, и мне нужен совет. В среднем использование библиотеки будет включать несколько вызовов api в одном запросе. Например, один вызов api для захвата пользователя из стороннего сервиса, а затем другой вызов для использования этого пользователя для захвата его / ее фотографий. Каждый вызов API получит свою собственную оболочку библиотечного метода с дополнительной логикой для обработки ошибок / тайм-аутов, но мой самый большой вопрос заключается в том, должна ли библиотека создаваться как синглтон, содержащий состояние, или просто как серия методов класса.
Например:
user_id = ThirdParty.get_user("abc@gmail.com")
photos = ThirdParty.get_photos(user_id)
или
thirdpartyservice = ThirdPartyService.new("abc@gmail.com")
photos = thirdpartyservice.get_photos
Это не обязательно должен быть точный дизайн библиотеки, но я просто запутался в плюсах / минусах каждого подхода. Любая помощь была бы замечательной!
Кстати, я использую ruby!
Комментарии:
1. Что касается вопроса, связанного с созданием библиотеки в виде синглтона, хорошо бы сделать ее статическим классом со статическими методами, потому что я понимаю, что состояние библиотечного класса не обязательно поддерживать.
Ответ №1:
Я бы хотел, чтобы библиотека содержала состояние, поскольку это снижает сложность кода на стороне пользователя (и это то, что API должен делать, повышать простоту). При таком подходе пользователю не нужно отслеживать этот user_id, поскольку библиотека сохраняет его состояние.
Если пользователю действительно нужен их user_id (или любые другие данные, которые хранит библиотека), вы можете просто создать attr_reader
в своей библиотеке, чтобы предоставить эти данные.
Чтобы добавить гибкость для метода get_photos, вы можете сделать что-то вроде:
class ThirdPartyService
def get_photos(user_id=@id_stored_in_library)
# do work
end
end
Таким образом, по умолчанию используется сохраненный идентификатор, однако это добавляет гибкости в том, что пользователь может указать идентификатор пользователя, если он того пожелает.
Ответ №2:
Вам нужно состояние (хост и т.д.) И поведение, основанное на этом состоянии, Поэтому вы должны использовать объекты, а не один одноэлементный объект.
Как уже упоминалось, вы не должны называть методы как get_photos
, просто photos
.
Комментарии:
1. Я согласен со стандартами именования. С точки зрения хоста и т.д., Вся эта информация постоянна. Информация о хосте и токене oauth одинакова для каждого вызова. Вы все еще думаете, что мне не следует использовать singleton?
Ответ №3:
Я считаю, что наилучшей практикой является использование provider и services для возможности не привязываться к определенному поставщику услуг. Вместо простого переноса библиотеки вы можете захотеть немного абстрагировать ее и по умолчанию разрешить использовать только одного поставщика услуг.
Хотя наследование на самом деле не требуется в языке с динамической типизацией, таком как Ruby, это может помочь конкретизировать «почему».
class MailProvider
def initialize(args); raise "Not Implemented"; end
def send_mail(args); raise "Not Implemented"; end
end
class SendGridService < MailProvider
def initialize(args)
# Use args here
end
def send_mail(args)
# Use SendGrid's API or Gem here
end
end
Тогда в вашем коде может быть что-то вроде этого:
config.mail_provider = SendGridService.new({
username: ENV['SENDGRID_USERNAME'],
password: ENV['SENDGRID_PASSWORD']
})
config.mail_provider.send_mail({ subject: 'woot', message: 'Look ma, I did it!' })
Затем, шесть месяцев спустя, когда вашим пользователям понравится ваш Gem / library, но они захотят поддержки MailChimp, вы можете просто создать второй сервис «MailChimpService» и разрешить своим клиентам использовать нового поставщика.
Ответ №4:
Вместо методов get_ set_ будет лучше использовать геттеры и установщики. Это стандарт ruby (не уверен, но методы get_ и set_ я видел только один раз в коде ruby).
Если вам не нужно сохранять некоторое состояние между запросами, сделайте его статичным. Но это зависит от многих факторов. Можете ли вы сказать нам, какой API вам нужно обернуть?