2012-11-23 262 views
2

如何在Java中使用Python中的observer/observable工具編寫程序? 我會在Java中寫下如下內容。觀察者python中的可觀察類

import java.util.Observable; 
import java.util.Observer; 


public class ObservDemo extends Object { 
    MyView view; 
    MyModel model; 

    public ObservDemo() { 

    view = new MyView(); 
    model = new MyModel(); 
    model.addObserver(view); 

    } 

    public static void main(String[] av) { 
    ObservDemo me = new ObservDemo(); 
    me.demo(); 
    } 

    public void demo() { 
    model.changeSomething(); 
    } 

    /** The Observer normally maintains a view on the data */ 
    class MyView implements Observer { 
    /** For now, we just print the fact that we got notified. */ 
    public void update(Observable obs, Object x) { 
     System.out.println("update(" + obs + "," + x + ");"); 
    } 
    } 

    /** The Observable normally maintains the data */ 
    class MyModel extends Observable { 
    public void changeSomething() { 
     // Notify observers of change 
     setChanged(); 
     notifyObservers(); 
    } 
    } 
} 

(此代碼是從以下鏈接 http://www.java2s.com/Code/Java/Design-Pattern/AsimpledemoofObservableandObserver.htm採取)

我怎麼在這樣的事情做到在Python?

+1

Python不是Java(幸運的是)。標準庫中沒有事件發佈者/訂閱者庫,但是有很多方法可以在沒有庫的情況下完成此操作。實際上太多了,你想達到什麼目的? –

+0

http://code.activestate.com/recipes/131499-observer-pattern/ –

+0

我正試圖編寫一個程序,它同時充當服務器(比如服務器A)和客戶端。首先客戶端發送一些消息到外部服務器(比如服務器B)。然後該服務器將消息廣播到我們自己的服務器。我的服務器(A)應該根據它從服務器B得到的回覆來操作我的客戶端。在這種情況下,我需要讓我的服務器可觀察,並且我的客戶端觀察者。我的客戶端根據服務器中某些變量的值進行操作。因此,只要在我的服務器中更改值,就應該通知它。我怎樣才能實現這樣的功能? – maheshakya

回答

4

首先,正如Martijn Pieters所說,Python不是Java。 這意味着你可能不需要整個觀察者/觀察模式,但可以把它歸結爲一個更簡化的版本。最後,我將展示的東西多一點pythonesque,但仍然是一個非常基本的Java實現,你可以嘗試這樣的事:

class Observer(object): 
    def notify(self,*args,**kwargs): 
     print args,kwargs 

class Target(object): 
    def __init__(self,*observers): 
     self.observes = observers 

    #this notify for every access to the function 
    def event(self,data): 
     for obs in self.observes: 
      obs.notify('event',data) 
     print "event with",data 

t = Target(Observer()) 
t.event(1) 
#('event', 1) {} 
#event with 1 

否則,你可以用一個裝飾實現它,那是相當相似的:

def observe(f): 
    def decorated(self,*args,**kwargs): 
     for obs in self.observes: 
      obs.notify('event',*args,**kwargs) 
     return f(self,*args,**kwargs) 
    return decorated 

class Target(object): 
    def __init__(self,*observers): 
     self.observes = observers 

    @observe 
    def otherevent(self,data): 
     print "other event with",data 

現在,所有這些方法都有效,但它們不是pythonic。想到以pythonic的方式實現這樣的東西的最好方法是實現一個包裝器,它檢查屬性訪問並調用回調函數(可以是觀察者的通知函數,但這是一種更一般的方法)

class Wrapper(object): 
    def __init__(self,wrapped,*callbacks): 
     self.wrapped = wrapped 
     self.callbacks = callbacks 

    def __getattr__(self,name): 
     res = self.wrapped.__getattribute__(name) 
     if not callable(res): 
      return res 
     def wrap(*args,**kwargs): 
      for c in self.callbacks: 
       c(self.wrapped,f,*args,**kwargs) 
      return res(*args,**kwargs) 
     return wrap 

    def __str__(self): 
     return self.wrapped.__str__() 

#in this example I will keep a record of each call performed on a list 
called = [] 
#this is the list 
a = [] 
#and this is the wrapped list 
w = Wrapper(a,lambda f,v,ign: called.append((f,v))) 
#I append an element to the wrapper 
w.append(1) 
#and I can see that it modify the original list 
print a 
#the print of the wrapped is well behaved, having defined the __str__ function 
print w 
#and we can see which function we called and which were the parameters 
print called 

這種做法是小有一點更令人費解,因爲你必須重定向手動所有的魔術方法,但這樣更強大,因爲允許實現觀察者模式的任何類型的對象,附加到任何兼容的功能,無需需要指定一個通用的觀察類。有很多方法可以自動重定向所有的魔法函數調用,但它有點複雜,只會混淆主要點。當你在python中工作時,忘記java的最快速度,它會變得更有趣。我建議你閱讀這片:

http://dirtsimple.org/2004/12/python-is-not-java.html

好運與你的工作!

+1

我不知道什麼是第三種方式更pythonic。當你需要觀察者模式時,你可能會有一個更大的體系結構而不僅僅是一個列表,並且想要準確控制何時以及如何通知觀察者。在這方面,前兩種解決方案更好地閱讀,使用和維護imo。 –