2009-08-23 42 views
61

Tại sao Borg pattern tốt hơn so với Singleton pattern?Tại sao mẫu Borg tốt hơn mẫu Singleton trong Python

Tôi hỏi vì tôi không thấy chúng dẫn đến bất kỳ điều gì khác biệt.

Borg:

class Borg: 
    __shared_state = {} 
    # init internal state variables here 
    __register = {} 
    def __init__(self): 
    self.__dict__ = self.__shared_state 
    if not self.__register: 
     self._init_default_register() 

Singleton:

class Singleton: 
    def __init__(self): 
    # init internal state variables here 
    self.__register = {} 
    self._init_default_register() 

# singleton mechanics external to class, for example this in the module 
Singleton = Singleton() 

Những gì tôi muốn hiển thị ở đây là đối tượng phục vụ, cho dù thực hiện như Borg hoặc Singleton, có một trạng thái nội bộ không tầm thường (nó cung cấp một số dịch vụ dựa trên nó) (Tôi có nghĩa là nó phải là một cái gì đó hữu ích nó không phải là một Singleton/Borg chỉ để cho vui).

Và trạng thái này phải được đặt trước. Tại đây việc triển khai Singleton đơn giản hơn vì chúng tôi xử lý init làm thiết lập trạng thái toàn cầu. Tôi thấy nó khó xử khi đối tượng Borg phải truy vấn trạng thái bên trong của nó để xem liệu nó có nên tự cập nhật hay không.

Tình trạng nội bộ càng trở nên tồi tệ hơn. Ví dụ, nếu đối tượng phải lắng nghe tín hiệu teardown của Application để lưu đăng ký của nó vào đĩa, thì việc đăng ký đó chỉ nên được thực hiện một lần, và điều này dễ dàng hơn với Singleton.

+1

Mẫu Borg?^_^Lần đầu tiên tôi nghe nói về nó là http://c2.com/cgi/wiki?MonostatePattern –

+8

Kiếm tiền? Chúng tôi là Martellis. Chúng tôi nói Borg. – u0b34a0f6ae

Trả lời

46

Lý do thực sự khiến borg khác với phân lớp con.

Nếu bạn phân lớp một borg, đối tượng của lớp con có cùng trạng thái với đối tượng lớp cha mẹ, trừ khi bạn ghi đè rõ ràng trạng thái được chia sẻ trong lớp con đó. Mỗi lớp con của mẫu đơn có trạng thái riêng và do đó sẽ tạo ra các đối tượng khác nhau.

Cũng trong mẫu đơn, các đối tượng thực sự giống nhau, không chỉ trạng thái (mặc dù trạng thái là thứ duy nhất thực sự quan trọng).

+1

> Cũng trong mẫu đơn, các đối tượng thực sự giống nhau, không chỉ trạng thái (mặc dù trạng thái là thứ duy nhất thực sự quan trọng) Tại sao lại là một điều xấu? – agiliq

+0

câu hỏi hay là uswaretech, nó là một phần của câu hỏi của tôi ở trên. Điều đó nói xấu như thế nào? – u0b34a0f6ae

+2

Tôi không nói đó là một điều xấu. Đó là một quan sát ít quan tâm về sự khác biệt. Xin lỗi vì sự nhầm lẫn. Đôi khi singleton sẽ được tốt hơn infact, nếu ví dụ bạn làm bất kỳ kiểm tra trên các đối tượng id id (obj), mặc dù điều này là hiếm. –

13

Nó không phải là. Những gì thường không được khuyến cáo là một mô hình như thế này trong python:

class Singleton(object): 

_instance = None 

def __init__(self, ...): 
    ... 

@classmethod 
def instance(cls): 
    if cls._instance is None: 
    cls._instance = cls(...) 
    return cls._instance 

nơi bạn sử dụng một phương pháp lớp để lấy dụ thay vì hàm tạo. Lập trình meta meta của Python cho phép các phương thức tốt hơn nhiều, ví dụ: ảnh trên Wikipedia:

class Singleton(type): 
    def __init__(cls, name, bases, dict): 
     super(Singleton, cls).__init__(name, bases, dict) 
     cls.instance = None 

    def __call__(cls, *args, **kw): 
     if cls.instance is None: 
      cls.instance = super(Singleton, cls).__call__(*args, **kw) 

     return cls.instance 

class MyClass(object): 
    __metaclass__ = Singleton 

print MyClass() 
print MyClass() 
+0

+1 Mô hình Monostate (Borg) là _worse_ hơn Singleton (có, có thể) vì private a = new Borg(); private b = new Borg(); b.mutate(); và một thay đổi! Làm thế nào khó hiểu là? –

+4

Tốt nhất/tệ hơn? Điều đó sẽ phụ thuộc vào usecase của bạn sẽ không nó. Tôi có thể nghĩ đến một số trường hợp bạn muốn trạng thái được bảo tồn như thế. – RickyA

+4

Đây không phải là vấn đề, @MichaelDeardeuff. Đây là _intended behaviour_. Chắc họ giống nhau. Một vấn đề IMHO trong mẫu borg là, nếu bạn thêm một số biến khởi tạo trong phương thức Borg .__ init__, như 'self.text =" "', sau đó thay đổi đối tượng đó như 'borg1.text =" blah "' và sau đó khởi tạo một đối tượng mới 'borg2 = Borg()" - wham! tất cả các thuộc tính borg1 được khởi tạo trong __init__ đều bị roi, vì vậy việc khởi tạo là không thể - hoặc tốt hơn: Trong mẫu Borg, bạn KHÔNG THỂ khởi tạo các thuộc tính thành viên trong phương thức __init__! – nerdoc

7

Lớp học về cơ bản mô tả cách bạn có thể truy cập (đọc/ghi) trạng thái bên trong của đối tượng.

Trong mẫu đơn, bạn chỉ có thể có một lớp duy nhất, tức là tất cả các đối tượng của bạn sẽ cung cấp cho bạn các điểm truy cập giống nhau cho trạng thái được chia sẻ. Điều này có nghĩa là nếu bạn phải cung cấp API mở rộng, bạn sẽ cần phải viết một trình bao bọc, bao quanh đơn lẻ

Trong mẫu borg bạn có thể mở rộng lớp "borg" cơ sở và do đó thuận tiện hơn mở rộng API cho sở thích của bạn.

7

Chỉ tốt hơn trong một vài trường hợp bạn thực sự có sự khác biệt. Giống như khi bạn phân lớp. Các mô hình Borg là cực kỳ bất thường, tôi đã không bao giờ cần nó cho thực tế trong mười năm lập trình Python.

17

Trong python nếu bạn muốn một "đối tượng" duy nhất mà bạn có thể truy cập từ bất cứ đâu chỉ cần tạo một lớp Unique chỉ chứa các thuộc tính tĩnh, @staticmethod s và @classmethod s; bạn có thể gọi nó là Mẫu duy nhất. Ở đây tôi thực hiện và so sánh 3 mẫu:

Unique

#Unique Pattern 
class Unique: 
#Define some static variables here 
    x = 1 
    @classmethod 
    def init(cls): 
     #Define any computation performed when assigning to a "new" object 
     return cls 

Singleton

#Singleton Pattern 
class Singleton: 

    __single = None 

    def __init__(self): 
     if not Singleton.__single: 
      #Your definitions here 
      self.x = 1 
     else: 
      raise RuntimeError('A Singleton already exists') 

    @classmethod 
    def getInstance(cls): 
     if not cls.__single: 
      cls.__single = Singleton() 
     return cls.__single 

Borg

#Borg Pattern 
class Borg: 

    __monostate = None 

    def __init__(self): 
     if not Borg.__monostate: 
      Borg.__monostate = self.__dict__ 
      #Your definitions here 
      self.x = 1 

     else: 
      self.__dict__ = Borg.__monostate 

thử nghiệm

#SINGLETON 
print "\nSINGLETON\n" 
A = Singleton.getInstance() 
B = Singleton.getInstance() 

print "At first B.x = {} and A.x = {}".format(B.x,A.x) 
A.x = 2 
print "After A.x = 2" 
print "Now both B.x = {} and A.x = {}\n".format(B.x,A.x) 
print "Are A and B the same object? Answer: {}".format(id(A)==id(B)) 


#BORG 
print "\nBORG\n" 
A = Borg() 
B = Borg() 

print "At first B.x = {} and A.x = {}".format(B.x,A.x) 
A.x = 2 
print "After A.x = 2" 
print "Now both B.x = {} and A.x = {}\n".format(B.x,A.x) 
print "Are A and B the same object? Answer: {}".format(id(A)==id(B)) 


#UNIQUE 
print "\nUNIQUE\n" 
A = Unique.init() 
B = Unique.init() 

print "At first B.x = {} and A.x = {}".format(B.x,A.x) 
A.x = 2 
print "After A.x = 2" 
print "Now both B.x = {} and A.x = {}\n".format(B.x,A.x) 
print "Are A and B the same object? Answer: {}".format(id(A)==id(B)) 

Output:

SINGLETON

At first B.x = 1 and A.x = 1 
After A.x = 2 
Now both B.x = 2 and A.x = 2 

Are A and B the same object? Answer: True 

BORG 

At first B.x = 1 and A.x = 1 
After A.x = 2 
Now both B.x = 2 and A.x = 2 

Are A and B the same object? Answer: False 

UNIQUE 

At first B.x = 1 and A.x = 1 
After A.x = 2 
Now both B.x = 2 and A.x = 2 

Are A and B the same object? Answer: True 

Theo tôi, thực hiện duy nhất là dễ nhất, sau đó Borg và cuối cùng Singleton với một số xấu xí của hai chức năng cần thiết cho định nghĩa của nó.

0

Ngoài ra, mẫu giống Borg cho phép người dùng của lớp lựa chọn nếu họ muốn chia sẻ trạng thái hoặc tạo một cá thể riêng biệt. (cho dù đây có phải là ý tưởng hay hay không là một chủ đề riêng)

class MayBeBorg: 
    __monostate = None 

    def __init__(self, shared_state=True, ..): 
     if shared_state: 

      if not MayBeBorg.__monostate: 
       MayBeBorg.__monostate = self.__dict__ 
      else: 
       self.__dict__ = MayBeBorg.__monostate 
       return 
     self.wings = .. 
     self.beak = .. 
Các vấn đề liên quan