2011-08-22 36 views
10

Tôi có một lớp yêu cầu một API từ xa. Tôi muốn có thể giảm số lượng cuộc gọi mà tôi đang thực hiện. Một số phương thức trong lớp của tôi thực hiện các cuộc gọi API giống nhau (nhưng vì các lý do khác nhau), vì vậy I'ld giống như khả năng cho họ 'chia sẻ' một phản hồi API được lưu trong bộ nhớ cache. Tôi không hoàn toàn chắc chắn nếu nó có thêm Pythonic để sử dụng các tham số tùy chọn hoặc sử dụng nhiều phương pháp, vì các phương thức có một số tham số cần thiết nếu chúng đang thực hiện cuộc gọi API.Python - Tốt hơn để có nhiều phương pháp hoặc nhiều tham số tùy chọn?

Dưới đây là những người phê duyệt như tôi thấy chúng, bạn nghĩ điều gì là tốt nhất?

class A: 

    def a_method(item_id, cached_item_api_response = None): 
    """ Seems awkward having to supplied item_id even 
     if cached_item_api_response is given 
    """ 
    api_response = None 
    if cached_item_api_response: 
     api_response = cached_item_api_response 
    else: 
     api_response = ... # make api call using item_id 

    ... #do stuff 

Hoặc này:

class B: 

    def a_method(item_id = None, cached_api_response = None): 
    """ Seems awkward as it makes no sense NOT to supply EITHER 
     item_id or cached_api_response 
    """ 
    api_response = None 
    if cached_item_api_response: 
     api_response = cached_item_api_response 
    elif item_id: 
     api_response = ... # make api call using item_id 
    else: 
     #ERROR 

    ... #do stuff 

Hoặc là này thích hợp hơn?

class C: 
    """Seems even more awkward to have different method calls""" 

    def a_method(item_id): 
     api_response = ... # make api call using item_id 
     api_response_logic(api_response) 

    def b_method(cached_api_response): 
     api_response_logic(cached_api_response) 

    def api_response_logic(api_response): 
     ... # do stuff 

Trả lời

5

Thông thường khi viết một phương pháp có thể tranh luận rằng một phương pháp/đối tượng nên làm một việc và nó nên làm tốt. Nếu phương pháp của bạn nhận được nhiều hơn và nhiều hơn nữa các thông số đòi hỏi nhiều hơn và nhiều hơn nữa ifs trong mã của bạn có thể có nghĩa là mã của bạn đang làm nhiều hơn thì một điều. Đặc biệt là nếu các thông số đó kích hoạt hành vi hoàn toàn khác nhau. Thay vào đó có thể hành vi tương tự có thể được tạo ra bằng cách có các lớp khác nhau và có các phương thức quá tải.

Có lẽ bạn có thể sử dụng một cái gì đó như:

class BaseClass(object): 
    def a_method(self, item_id): 
     response = lookup_response(item_id) 
     return response 

class CachingClass(BaseClass): 
    def a_method(self, item_id): 
     if item_id in cache: 
      return item_from_cache 
     return super(CachingClass, self).a_method(item_id) 

    def uncached_method(self, item_id) 
     return super(CachingClass, self).a_method(item_id) 

Bằng cách đó bạn có thể chia logic như thế nào để tra cứu các phản ứng và bộ nhớ đệm trong khi cũng làm cho nó linh hoạt cho người sử dụng của API để quyết định nếu họ muốn khả năng bộ nhớ đệm hay không.

+0

Cảm ơn bạn đã chỉnh sửa, nhưng thông thường tôi sẽ đề xuất sử dụng ủy quyền thay vì thừa kế vì nó làm cho các lớp linh hoạt hơn. – Rickard

+0

Nếu đây không phải là ý định của bạn, xin lỗi vì đã thay đổi nó. Nó chỉ là một câu hỏi Python và mã của bạn không phải là Python vì vậy tôi đã thực hiện tốt nhất của tôi đoán - cảm thấy tự do để cuộn nó trở lại hoặc thay đổi nó để phản ánh ý định của bạn. (Tốt câu trả lời bất kỳ cách nào, đã có +1 của tôi) – agf

2

Không có gì sai với phương pháp được sử dụng trong class B của bạn. Để làm cho nó rõ ràng hơn trong nháy mắt mà bạn thực sự cần phải bao gồm một trong hai item_id hoặc cached_api_response, tôi sẽ đặt kiểm tra lỗi đầu tiên:

class B: 

    def a_method(item_id = None, cached_api_response = None): 
     """Requires either item_id or cached_api_response""" 

     if not ((item_id == None)^(cached_api_response == None)): 
      #error 

     # or, if you want to allow both, 
     if (item_id == None) and (cached_api_response == None): 
      # error 

     # you don't actually have to do this on one line 
     # also don't use it if cached_item_api_response can evaluate to 'False' 
     api_response = cached_item_api_response or # make api call using item_id 

     ... #do stuff 
1

Cuối cùng đây là phán quyết phải được thực hiện cho từng trường hợp. Tôi sẽ hỏi bản thân mình, mà trong hai điều này phù hợp chặt chẽ hơn:

  1. Hai thuật toán hoặc hành động hoàn toàn khác nhau, với ngữ nghĩa hoàn toàn khác nhau, mặc dù họ có thể được thông qua thông tin tương tự
  2. Một ý tưởng khái niệm duy nhất, với ngữ nghĩa phù hợp , nhưng với sắc thái dựa trên đầu vào

Nếu lần đầu tiên gần nhất, hãy sử dụng các phương pháp riêng biệt. Nếu thứ hai là gần nhất, đi với các đối số tùy chọn. Bạn thậm chí có thể thực hiện một phương thức đơn lẻ bằng cách kiểm tra kiểu của các đối số để tránh truyền các đối số bổ sung.

1

Đây là mẫu chống OO.

class API_Connection(object): 
    def do_something_with_api_response(self, response): 
     ... 

    def do_something_else_with_api_response(self, response): 
     ... 

Bạn có hai phương pháp trên một trường hợp và bạn đang chuyển trạng thái giữa chúng một cách rõ ràng? Tại sao những phương pháp này và không phải chức năng trần trong một mô-đun?

Thay vào đó, hãy suy nghĩ về việc sử dụng đóng gói để giúp bạn bằng cách có thể hiện của lớp sở hữu phản hồi api.

Ví dụ:

class API_Connection(object): 
    def __init__(self, api_url): 
     self._url = api_url 
     self.cached_response = None 

    @property 
    def response(self): 
     """Actually use the _url and get the response when needed.""" 
     if self._cached_response is None: 
      # actually calculate self._cached_response by making our 
      # remote call, etc 
      self._cached_response = self._get_api_response(self._url) 
     return self._cached_response 

    def _get_api_response(self, api_param1, ...): 
     """Make the request and return the api's response""" 

    def do_something_with_api_response(self): 
     # just use self.response 
     do_something(self.response) 

    def do_something_else_with_api_response(self): 
     # just use self.response 
     do_something_else(self.response) 

Bạn có bộ nhớ đệm và bất kỳ phương pháp mà cần phản ứng này có thể chạy trong bất kỳ thứ tự mà không làm nhiều yêu cầu api vì phương pháp đầu tiên mà cần self.response sẽ tính toán nó và mỗi khác sẽ sử dụng giá trị được lưu trong bộ nhớ cache. Hy vọng rằng nó rất dễ dàng để tưởng tượng mở rộng này với nhiều URL hoặc các cuộc gọi RPC. Nếu bạn có nhu cầu cho rất nhiều phương pháp lưu trữ các giá trị trả lại của chúng như là response ở trên thì bạn nên xem xét một trình trang trí ghi nhớ cho các phương pháp của mình.

+0

Tôi thích khái niệm tổng thể, nhưng tôi thấy một số dificulties nhận được từ 'do_something' phương pháp để' _get_api_response' phương pháp nếu có các tham số khác nhau giữa các cuộc gọi. Tuy nhiên, vẫn đáng +1. –

0

Phản hồi được lưu trong bộ nhớ cache phải được lưu trong trường hợp, không được chuyển xung quanh như túi Skittles - nếu bạn bỏ nó?

Có phải item_id duy nhất cho mỗi trường hợp hoặc có thể tạo một truy vấn cho nhiều hơn một trường hợp không? Nếu nó có thể có nhiều hơn một, tôi muốn đi với một cái gì đó như thế này:

class A(object): 

    def __init__(self): 
     self._cache = dict() 

    def a_method(item_id): 
     """Gets api_reponse from cache (cache may have to get a current response). 
     """ 
     api_response = self._get_cached_response(item_id) 
     ... #do stuff 

    def b_method(item_id): 
     """'nother method (just for show) 
     """ 
     api_response = self._get_cached_response(item_id) 
     ... #do other stuff 

    def _get_cached_response(self, item_id): 
     if item_id in self._cache: 
      return self._cache[ item_id ] 
     response = self._cache[ item_id ] = api_call(item_id, ...) 
     return response 

    def refresh_response(item_id): 
     if item_id in self._cache: 
      del self._cache[ item_id ] 
     self._get_cached_response(item_id) 

Và nếu bạn có thể có để có được các thông tin mới nhất về item_id, bạn có thể có một phương pháp refresh_response.

Các vấn đề liên quan