设计模式(四):代理模式
Head Fisrt设计模式上面有一句话:代理模式要做的:控制和管理访问。代理类似于明星的经纪人,可以处理来访的需求,但不影响明星本人的行为。
下面的例子,TV是对电视的操作,有channel表示当前的频道,power表示电视电源开关。通过proxy代理,可以记录曾经的操作,如打开的次数,转频道的次数等。
import random import unittest class TV(object): """docstring for TV""" def __init__(self, brand): self._brand = brand self._channel = None self._power = None @property def brand( self ): return self._brand @property def channel( self ): return self._channel @channel.setter def channel( self, value ): self._channel = value def power( self ): if "on" == self._power: self._power = "off" else: self._power = "on" def showPower( self ): return self._power class TestTvClass( unittest.TestCase ): """docstring for TestBasicClass""" def setUp( self ): self._tv = TV( "Apple" ) def test_tv_class_has_attribute( self ): self.assertTrue( hasattr( self._tv, 'brand' ) ) self.assertTrue( hasattr( self._tv, 'channel' ) ) self.assertTrue( hasattr( self._tv, 'power' ) ) self.assertTrue( hasattr( self._tv, 'showPower' ) ) def test_tv_initiate_state( self ): self.assertEqual( 'Apple', self._tv.brand ) self.assertEqual( None, self._tv.showPower() ) self.assertEqual( None, self._tv.channel ) def test_turn_on_tv_to_channel_10( self ): self._tv.power() self._tv.channel = 10 self.assertEqual( 'on', self._tv.showPower() ) self.assertEqual( 10, self._tv.channel ) def test_turn_off_tv( self ): self._tv.power() self._tv.channel = 10 self._tv.power() self.assertEqual( 'off', self._tv.showPower() ) self.assertEqual( 10, self._tv.channel ) def tearDown( self ): pass class Proxy(object): """docstring for Proxy""" def __init__(self, tv_object): self._records = [] self._obj = tv_object def __setattr__( self, attrname, value ): if '_' == attrname[0]: object.__setattr__( self, attrname, value ) else: self._records.append( attrname ) self._obj.__setattr__( attrname, value ) def __getattr__( self, attrname ): if '_' == attrname[0]: return object.__getattribute__( self, attrname ) else: self._records.append( attrname ) return self._obj.__getattribute__( attrname ) def showRecord( self ): return self._records def number_of_operate( self, attrname ): return self._records.count( attrname ) class TestProxy( unittest.TestCase ): """docstring for TestProxy""" def setUp( self ): self._tv = Proxy( TV( "Apple" ) ) def test_proxy_has_attribute( self ): self.assertTrue( hasattr( self._tv, 'showRecord' ) ) def test_handle_property_from_proxy_to_tv( self ): self._tv.power() self._tv.channel = 10 self.assertEqual( 10, self._tv.channel ) self.assertEqual( 'on', self._tv.showPower() ) def test_get_operate_tv_record( self ): self._tv.power() self._tv.channel = 20 self.assertEqual( ['power', 'channel'], self._tv.showRecord() ) self.assertEqual( 20, self._tv.channel ) def test_get_operate_number( self ): self._tv.power() self._tv.channel = 10 self.assertEqual( 1, self._tv.number_of_operate( 'power' ) ) self.assertEqual( 1, self._tv.number_of_operate( 'channel' ) ) if __name__ == '__main__': unittest.main()
下面是C++实现的一个虚代理的例子:如果直接打开一个图片,所花费的代价会比较大,那么,只要设定一个代理,用户先快速打开代理。然后等需要的时候再打开真正的图片。
View Code
#include <iostream> #include <string> using namespace std; class Image { public: Image( string name ) : m_imageName( name ){} virtual ~Image(){} virtual void Show(){} protected: string m_imageName; /* data */ }; class BigImage : public Image { public: BigImage( string name ) : Image( name ){} ~BigImage(){} void Show() { cout << "Show big image." << m_imageName << endl; } /* data */ }; class BigImageProxy : public Image { public: BigImageProxy( string name ) : Image( name ), m_bigImage( 0 ) {} ~BigImageProxy(){ delete m_bigImage; } void Show() { if ( NULL == m_bigImage ) { m_bigImage = new BigImage( m_imageName ); } m_bigImage->Show(); } /* data */ private: BigImage *m_bigImage; }; int main() { Image *image = new BigImageProxy( "proxy.jpg" ); image->Show(); delete image; return 0; }