<读书笔记> Thinking in python (Python 设计模式) 1. Singlton的c++与python的实现

1.由于python的天然的泛型特征,python 中没有接口继承,所有的继承都是实现继承,子类为了继承父类的实现。

 

2.Singlton 单件模式

  • singlton in c++

      下面看一个最简单的C++实现,它做到的是通过

      类static变量,以及将默认构造函数私有化

      从而使得只能有一个GlobalClass的实体存在

       1 #include <iostream>

 2  using   namespace  std;
 3 
 4  class  GlobalClass {
 5       public :
 6           static  GlobalClass *  instance();
 7           static   void  create();
 8           static   void  destroy();
 9           void  print() {
10              cout  <<   " haha "   <<  endl;
11          }
12       private :
13           static  GlobalClass *  s_instance;
14          GlobalClass();
15           ~ GlobalClass(){
16               // destroy();
17              cout  <<   " destruct "   <<  endl;
18 
19          }
20  };
21 
22  GlobalClass *  GlobalClass::s_instance  =  NULL;
23 
24  GlobalClass::GlobalClass() {
25      cout  <<   " construct global class "   <<  endl;
26  }
27  // GloblaClass::~GlobalClass() {
28  //     destroy();
29  //     cout << "destruct" << endl;
30  // }
31  GlobalClass *  GlobalClass::instance() {
32       return  s_instance;
33  }
34 
35  void  GlobalClass::create() {
36       if  ( ! s_instance)
37          s_instance  =   new  GlobalClass();
38  }
39 
40  void  GlobalClass::destroy() {
41      delete s_instance;
42      s_instance  =  NULL;
43      cout  <<   " delete ok "   <<  endl;
44  }
45 
46  int  main( int  argc,  char   * argv[])
47  {
48       // GlobalClass my_global_class;  //can't create by this
49      GlobalClass::create();
50      GlobalClass *  p_global_class  =  GlobalClass::instance();
51      p_global_class -> print();
52      GlobalClass::destroy();
53       return   0 ;
54  }
//result
construct global class
haha
destruct
delete ok

刚刚想到effective c++第四款,提到的的利用函数内部local static变量的方法。这样也可以给出一种Siglton的实现
 
  1  // file singlton.h
  2 
  3  #ifndef _SINGLTON_H_
  4  #define  _SINGLTON_H_
  5  #include  < iostream >
  6  using   namespace  std;
  7 
  8  class  GlobalClass {
  9       public :
 10           static  GlobalClass &  instance( int  weight  =   3 ){
 11               static  GlobalClass global_object(weight);
 12               return  global_object;
 13          }
 14           void  print() {
 15              cout  <<   " haha "   <<   this   <<  endl;
 16              cout  <<  m_weight  <<  endl  <<  endl;
 17          }
 18           ~ GlobalClass(){
 19              cout  <<   " destruct "   <<   this   <<  endl;
 20 
 21          }
 22           void  addOne() {
 23              m_weight  +=   1 ;
 24          }
 25 
 26       private :
 27          GlobalClass() {
 28              cout  <<    " construct global class "   <<   this   <<  endl;
 29 
 30          }
 31          GlobalClass( int  weight):m_weight(weight){ cout  <<   " construct global class with weight "   <<   this   <<  endl;}
 32          GlobalClass &   operator = const  GlobalClass & );
 33          GlobalClass( const  GlobalClass & );
 34           int  m_weight;
 35  };
 36  #endif
 37 
 38 
 39  // file use_singlton.h
 40  #ifndef USE_SIGLTON_H
 41  #define  USE_SIGLTON_H
 42 
 43  #include  " singlton.h "
 44  void  useSinglton();
 45   
 46  #endif
 47 
 48  // file use_singlton.cc
 49  #include  < iostream >
 50  #include  " use_singlton.h "
 51  using   namespace  std;
 52  void  useSinglton() {
 53      GlobalClass &  p_global_class  =  GlobalClass::instance( 16 );
 54      p_global_class.print();
 55      p_global_class.addOne();
 56      p_global_class.print();
 57 
 58      GlobalClass &  p_global_class2  =  GlobalClass::instance( 46 );
 59      p_global_class2.print();
 60      p_global_class2.addOne();
 61      p_global_class2.print();
 62  }
 63 
 64  // file test_singlton.cc
 65  #include  < iostream >
 66  #include  " singlton.h "
 67  #include  " use_singlton.h "
 68  using   namespace  std;
 69 
 70  int  main( int  argc,  char   * argv[])
 71  {
 72      cout  <<   " use singlton "   <<  endl;
 73      useSinglton();
 74 
 75      cout  <<   " wa ha ha  "   <<  endl;
 76      GlobalClass &  p_global_class  =  GlobalClass::instance( 4 );
 77      p_global_class.print();
 78      p_global_class.addOne();
 79      p_global_class.print();
 80 
 81      GlobalClass &  p_global_class2  =  GlobalClass::instance( 8 );
 82      p_global_class2.print();
 83      p_global_class2.addOne();
 84      p_global_class2.print();
 85 
 86      cout  <<   " ha ha wa "   <<  endl;
 87      useSinglton();    
 88 
 89       return   0 ;
 90  }
 91 
 92  // allen:~/study/design_pattern/singlton_test$ g++ -g -o test_singlton  test_singlton.cc use_singlton.cc 
 93  allen: ~/ study / design_pattern / singlton_test$ . / test_singlton 
 94  use singlton
 95  construct  global   class  with weight0x804a5c0
 96  haha0x804a5c0
 97  16
 98 
 99  haha0x804a5c0
100  17
101 
102  haha0x804a5c0
103  17
104 
105  haha0x804a5c0
106  18
107 
108  wa ha ha 
109  haha0x804a5c0
110  18
111 
112  haha0x804a5c0
113  19
114 
115  haha0x804a5c0
116  19
117 
118  haha0x804a5c0
119  20
120 
121  ha ha wa
122  haha0x804a5c0
123  20
124 
125  haha0x804a5c0
126  21
127 
128  haha0x804a5c0
129  21
130 
131  haha0x804a5c0
132  22
133 
134  destruct0x804a5c0
135 
用local static的这个方法也保证了只有一个实例的存在,不过仅供学习吧,不如第一种方案,毕竟有一个类类型的static变量的存在,
而且它只能在main介绍的时候才会被析构,上面的我们可以随时主动去析构对象。

Singlton的基本思想很简单,但是用C++实现,关于资源的释放,何时释放还是感觉很别扭的。
下面是网上找到的一个基于模版的singlton实现,可以方便的复用该框架,同时利用了shared_ptr,无需操心释放动态内存。
另外给出一个OPEMESH中的singlton模版的实现,它也是使用了产生一个类类型的static变量(用户需要的时候才会产生出来)。
这两种方式都会在main结束后析构掉siglton对象资源,如shared_ptr自动释放 new的资源,而OPEMESH的方法static的类对象会销毁(调用起析构函数).
//使用shared_ptr实现的singlton模版类
 
 1  #include  < iostream >
 2  #include  < tr1 / memory >
 3  using   namespace  std;
 4  using   namespace  std::tr1;
 5  template  < typename T >
 6  class  Singlton {
 7       public :
 8           static  T *  instance();
 9           static   void  create();
10           void  print() {
11               cout  <<   " haha "   <<  endl;
12          }
13           ~ Singlton() {
14              cout  <<   " destruct singlton "   <<  endl;
15          }
16       protected :
17          Singlton();
18       // private:
19       protected :
20           static  shared_ptr < T >  s_instance; 
21           // Singlton();
22  };
23  template  < typename T >
24  shared_ptr < T >  Singlton < T > ::s_instance;
25 
26  template  < typename T >
27  Singlton < T > ::Singlton() {
28      cout  <<   " construct singlton "   <<  endl;
29  }
30 
31  template  < typename T >
32  T *  Singlton < T > ::instance() {
33       return  s_instance. get ();
34  }
35 
36  template  < typename T >
37  void  Singlton < T > ::create() {
38       if  ( ! s_instance. get ())
39          s_instance.reset( new  T);
40 
41  }
42 
43  //  well 这里注意,我理解为Singlton<T>::create() 应该可以调用 MySinglton的私有函数,但事实上不行
44  //  因为理论上 还是调用基类的函数 Singlton<MySinglton>::create()
45  // class MySinglton : public Singlton<MySinglton> {
46  //      // private:
47  //     public:
48  //         MySinglton(){
49  //             cout << "construct my singlton" << endl;
50  //         }
51  //
52  // };
53  class  MySinglton :  public  Singlton < MySinglton >  {
54          friend   class  Singlton < MySinglton > ;
55       private :
56          MySinglton(){
57              cout  <<   " construct my singlton "   <<  endl;
58          }
59          MySinglton  *  MyInstance() {
60               return  s_instance. get ();
61          }
62  };
63 
64  // or can directyly define one class like MyClass1, and to not consider siglton part,
65  // than use Singlton<MyClass1>  is OK. May be typedef Singlton<MyClass1> MyClass1Singlton 
66  // and use MyClass1Siglton
67  int  main( int  argc,  char   * argv[])
68  {
69         
70      MySinglton::create();
71      MySinglton *  p_my_singlton  =  MySinglton::instance();
72      p_my_singlton -> print();
73       return   0 ;
74  }
75  /* result
76  construct singlton
77  construct my singlton
78  haha
79  destruct singlton
80  */
OPMESH的singlton模版类的实现,这个似乎更专业些:)

  
  1  // SingltonT.hh
  2  // =============================================================================
  3  //
  4  //   Implements a simple singleton template
  5  //
  6  // =============================================================================
  7 
  8 
  9  #ifndef __SINGLETON_HH__
 10  #define  __SINGLETON_HH__
 11 
 12 
 13  // === INCLUDES ================================================================
 14 
 15  //  OpenMesh
 16  #include  < OpenMesh / Core / System / config.h >
 17 
 18  //  STL
 19  #include  < stdexcept >
 20  #include  < iostream >
 21 
 22 
 23  // == NAMESPACES ===============================================================
 24 
 25 
 26  namespace  OpenMesh {
 27 
 28 
 29  // === IMPLEMENTATION ==========================================================
 30 
 31 
 32  /* * A simple singleton template.
 33      Encapsulates an arbitrary class and enforces its uniqueness.
 34  */
 35 
 36  template  < typename T >
 37  class  SingletonT
 38  {
 39  public :
 40 
 41     /* * Singleton access function.
 42        Use this function to obtain a reference to the instance of the 
 43        encapsulated class. Note that this instance is unique and created
 44        on the first call to Instance().
 45     */
 46 
 47     static  T &  Instance()
 48    {
 49       if  ( ! pInstance__)
 50      {
 51         //  check if singleton alive
 52         if  (destroyed__)
 53        {
 54      OnDeadReference();
 55        }
 56         //  first time request -> initialize
 57         else
 58        {
 59      Create();
 60        }
 61      }
 62       return   * pInstance__;
 63    }
 64 
 65 
 66  private :
 67 
 68     //  Disable constructors/assignment to enforce uniqueness
 69    SingletonT();
 70    SingletonT( const  SingletonT & );
 71    SingletonT &   operator = ( const  SingletonT & );
 72 
 73     //  Create a new singleton and store its pointer
 74     static   void  Create()
 75    {
 76       static  T theInstance;
 77      pInstance__  =   & theInstance;
 78    }
 79    
 80     //  Will be called if instance is accessed after its lifetime has expired
 81     static   void  OnDeadReference()
 82    {
 83       throw  std::runtime_error( " [Singelton error] - Dead reference detected!\n " );
 84    }
 85 
 86     virtual   ~ SingletonT()
 87    {
 88      pInstance__  =   0 ;
 89      destroyed__  =   true ;
 90    }
 91    
 92     static  T *      pInstance__;
 93     static   bool    destroyed__;
 94  };
 95 
 96 
 97 
 98  // =============================================================================
 99  //  namespace OpenMesh
100  // =============================================================================
101  #if  defined(OM_INCLUDE_TEMPLATES) && !defined(OPENMESH_SINGLETON_C)
102  #  define OPENMESH_SINGLETON_TEMPLATES
103  #  include  " SingletonT.cc "
104  #endif
105  // =============================================================================
106  #endif   //  __SINGLETON_HH__
107  // =============================================================================
108 
109 
110  // SingltonT.cc
111  // =============================================================================
112  //
113  //   Implements a simple singleton template
114  //
115  // =============================================================================
116 
117 
118  #define  OPENMESH_SINGLETON_C
119 
120 
121  // == INCLUDES =================================================================
122 
123 
124  //  header
125  #include  < OpenMesh / Core / Utils / SingletonT.hh >
126 
127 
128  // == NAMESPACES ===============================================================
129 
130 
131  namespace  OpenMesh {
132 
133 
134  // == SINGLETON'S DATA =========================================================
135 
136 
137  template  < class  T >  
138  T *  SingletonT < T > ::pInstance__  =   0 ;
139 
140  template  < class  T >
141  bool  SingletonT < T > ::destroyed__  =   false ;
142 
143 
144  // =============================================================================
145  //  namespace OpenMesh
146  // =============================================================================
147 
使用的时候如
typedef SingletonT<LoopSchemeMaskDouble>    LoopSchemeMaskDoubleSingleton;

  • singlton in python

      那么在python中,作者提到的singlton的概念得到了放宽,

           Alex Martelli makes the observation that what we really want with a
           Singleton is to have a single set of state data for all objects. That is, you
           could create as many objects as you want and as long as they all refer to
           the same state information then you achieve the effect of Singleton.

      你可以有任意多的对象,但是它们都指向相同的状态信息,即为singlton。Borg利用__dict__属性巧妙的实现了一个

      singlton 模式。



  
 1  class  Borg():
 2      shared_dict  =  {}
 3       def   __init__ (self):
 4          self. __dict__   =  self.shared_dict  
 5 
 6  class  Singleton(Borg):
 7       def   __init__ (self, arg):
 8          Borg. __init__ (self)
 9          self.val  =  arg
10       def   __str__ (self): 
11           print (self. __dict__ )
12           return  self.val
13 
14 
15  if   __name__   ==   ' __main__ ' :
16      x  =  Singleton( ' abc ' )
17      y  =  Singleton( ' def ' )
18       print (x)
19       print (y)
20 
21  output  =   '''
22  {'val': 'def'}
23  def
24  {'val': 'def'}
25  def
26  '''

这种方案,简洁清楚,并且很容易通过继承而复用。当然作者还提到许多其它的实现方法,对比下面的方法。

  1 class OnlyOne:

 2 
 3       class   __OnlyOne :
 4           def   __init__ (self, arg):
 5              self.val  =  arg
 6           def   __str__ (self):
 7               return   ' self '   +  self.val
 8               # return `self` + self.val
 9      instance  =  None
10       def   __init__ (self, arg):
11           if   not  OnlyOne.instance:
12              OnlyOne.instance  =  OnlyOne. __OnlyOne (arg)
13           else :
14              OnlyOne.instance.val  =  arg
15       def   __getattr__ (self, name):
16           return  getattr(self.instance, name)
17 
18 
19  =  OnlyOne( ' sausage ' )
20  print (x)
21  =  OnlyOne( ' eggs ' )
22  print (y)
23  =  OnlyOne( ' spam ' )
24  print (z)
25 
26  print (x)
27  print (y)
28  print (z)
29  print ( ' x ' )
30  print ( ' y '
31  print ( ' z '
32 
33  print (x.instance)
34  output  =   '''
35  selfsausage
36  selfeggs
37  selfspam
38  selfspam
39  selfspam
40  selfspam
41  x
42  y
43  z
44  selfspam
45  '''

你可能感兴趣的:(python)