2010-05-21 12 views
5

Zostało to wspomniane w innych odpowiedziach dotyczących uzyskiwania tego samego kodu działającego dla def get(self) i def post(self) dla dowolnego żądania. Zastanawiałem się, jakie techniki używają, myślałem o:Uruchamianie tego samego kodu dla get (self) jako post (self)

class ListSubs(webapp.RequestHandler): 
    def get(self): 
     self._run() 

    def post(self): 
     self._run() 

    def _run(self): 
     self.response.out.write("This works nicely!") 

Odpowiedz

11

Sugerowałbym zarówno ze względów teoretycznych i praktycznych, dlaczego podejście używasz (refaktoringu się wspólny kod do osobnej metody i nazywając go zarówno od słupka i uzyskać metody) przewyższa pozornie prostszą alternatywę polegającą na tym, że jedna z tych dwóch metod nazywa się drugą.

Z teoretycznego punktu widzenia "metoda A całkowicie deleguje do metody B" implikuje pojęcie "prymatu" lub "asymetrii" - decyzji projektowej, która, idąc do przodu, każda zmiana, która może być zastosowana do B, będzie nieuchronnie, nieodłącznie stosuje się również do A; że A może w przyszłości być nieznacznie spersonalizowane w odniesieniu do B (dodając jakiś dodatkowy kod przed i/lub po wywołaniu A do B), ale nigdy na odwrót. Kiedy nie ma powodu oczekiwać takiego prymatu, jest to zła decyzja dotycząca kodowania, aby umieścić to pojęcie w swoim kodzie. Ponieważ zarówno A, jak i B nazywają wspólną prywatną metodę C, unikasz łamania symetrii.

Niektórzy ludzie nie są zadowoleni z teoretycznych argumentów i wolą pragmatyczne: na szczęście w tym przypadku teoretyczne przekłada się na pragmatyczne całkiem bezpośrednio. Ponownie, jest to kwestia przyszłej ewolucji kodu: posiadanie zarówno A, jak i B wywołuje C, pozostawia wszystkie stopnie swobody, aby wykonać małe dostosowania (dodając kod przed i/lub po wywołaniu C) do jednego, obu lub żadnego A i B. Ponieważ nie wiesz, jakie części tej elastyczności będziesz potrzebował, a jej koszt pod względem prostoty jest niewielki, podjęcie prostej i elastycznej trasy jest wysoce pragmatyczne i wskazane.

Ostatni punkt pragmatyczny (stosując się do jednej z tych opcji): za każdym razem masz wzór takiego:

def amethod(self): 
    return cmethod(self) 

jesteś zwykle (skromnie) lepiej przeformułowującej to jako

amethod = cmethod 

This unika niepotrzebnego poziomu zagnieżdżania wywołań (płaska jest lepsza niż zagnieżdżona). Tak, klasa mogłaby z pożytkiem zostać zakodowane:

class ListSubs(webapp.RequestHandler): 

    def _run(self): 
     self.response.out.write("This works even better!") 

    get = post = _run 

Nic wielkiego, a będziesz miał byłaby powrotem do oryginalnego „zagnieżdżone” sposób, czy i kiedy trzeba zrobić, aby zastosować poprawek przed lub po wywołaniu zagnieżdżonego (od get do _run, itp.) lub potrzebujesz innych poprawek w debugowaniu (np. ustaw punkt przerwania w debugerze na post, ale bez wyzwalania punktu przerwania na get, itp.), ale ładne małe uproszczenie dla tamtych czasów, w których jest to wykonalne.

+1

Dzięki, to nie jest lekcja, o której zapomnę od jakiegoś czasu! –

2

Refaktoryzacja kodu, który działa na własnej funkcji/metoda jest właściwa metoda.

+0

OK, czy to w zasadzie to, co zrobiłem powyżej? –

+1

To prawda. –

2

Użyłem tego:

class ListSubs(webapp.RequestHandler): 
    def post(self): 
     self.response.out.write("This works nicely!") 
    def get(self): 
     self.post() 
+2

Podczas gdy to działa, działa lekko na Zasada Najmniejszego Zdziwienia. –

1

Jedną z rzeczy, których nie widziałem w odpowiedziach, do których dodam, jest to, dlaczego nie powinieneś tego robić. Jest dość powszechną zasadą, że zmienianie danych na serwerze HTTP GET jest złym pomysłem. Zmiana stanu serwera powinna zazwyczaj nastąpić poprzez POST. W rezultacie każdy adres URL, który jest używany zarówno w przypadku GET, jak i POST, powinien mieć określone działania, które różnią się w zależności od typu żądania. W3c ma również ładny overview of when to use GET vs. POST.

Mam tendencję do myślenia o GET i POST jak getter i seter. POST s zmienić dane, a GET s uzyskać dane. W związku z tym proste wyszukiwanie może przez cały dzień korzystać z GET, ale po zapisaniu ustawienia z powrotem na serwerze, należy wykonać POST.

Załóżmy na przykład, że masz adres URL posta na swoim blogu (example.com/blog/post-vs-get/). Następnie możesz użyć get(), aby uzyskać wpis na blogu i wyświetlić go na ekranie za pomocą ładnego formularza komentarza. W tym przykładzie mój formularz komentarza będzie POST wracać do tego samego adresu URL, wywołując metodę post(), która może przetworzyć formularz, a następnie zwrócić tę samą wyrenderowaną stronę.

class ListSubs(webapp.RequestHandler): 
    def post(self): 
     comment = cgi.escape(self.request.get('comment')) 
     ## Do magic with our comment. 
     self.get() ## Go off and return the rendered page. 
    def get(self): 
     ## Get the blog post out of the data store and render a page. 
     self.response.out.write("""<html> 
       <body> 
       <p>My awesome blog post!</p> 
       <form method="post"> 
        <h1>Comment</h1> 
        <textarea name="comment" rows="3" cols="60"></textarea> 
        <input type="submit" value="Comment"> 
       </form> 
       </body> 
      </html>""") 

Daje czysty podział pracy między renderowaniem strony i przetwarzaniem danych POST. Uniemożliwia to także niepoprawne sprawdzenie kodu i/lub przetwarzanie kodu na żądanie bez danych. Moim zdaniem to oddzielenie obowiązków ułatwia także debugowanie i utrzymywanie kodu.

+0

W oddzielnej notatce powinieneś wykonać przekierowanie po POST, aby zapobiec przypadkowemu odświeżeniu strony i ponownemu opublikowaniu. –