分享

单例是个好的设计模式吗?

 知识情报院 2022-04-26
单例是个好的设计模式吗?

设计模式是思考面向对象中,如何在代码类之间交互的好方法。但是经典的单例模式真的是个好的设计模式吗?:你应该使用它吗?或者有更好的选择?

经典的单例模式是一个类,当你创建类的实例时,它总是为您提供相同的对象。它用于确保一个类的所有用户都使用同一个对象。

单例的第一个问题是它鼓励你将两种不同的想法混合到一个类中。第一个想法是你的类是关于什么的。假设你正在编写一个国际象棋游戏。你的 ChessBoard 类应该只关注棋盘。第二个想法是你的程序只需要一种棋子。这不是棋盘固有的事实,因此不应将其编码到你的 ChessBoard 类中。

如果你的程序只需要一个某类型的对象,你可以只创建一个:

class ChessBoard:
    def __init__(self):
        ...

the_chess_board = ChessBoard()

如果要集中管理实例,可以使用函数来管理全局:

_the_chess_board  =  None 

def  the_chess_board (): 
    global  _the_chess_board 
    if  _the_chess_board  is  None : 
        _the_chess_board  =  ChessBoard () 
    return  _the_chess_board

或者让 functools 为您完成:

@functools.cache         # 3.9 新增
def  the_chess_board (): 
    return  ChessBoard ()

如果你仍然真的希通过类管理单个实例,则可以将该函数转换为类方法:

class ChessBoard:
    def __init__(self):
        ...

    @classmethod
    @functools.cache
    def the_board(cls):
        return cls()

这些方式比通用的思路来实现单例更简单。它们还有一个额外的好处,即类的用户清楚地知道他们正在访问一个全局实例。这是单例的另一个问题:它给了你一个充满谎言的类。调用单例类看起来像是在创建新对象实例,但实际上并非如此。

这些方法还可以让你在需要时仍然创建新实例。类似 ChessBoard 测试示例将需要创建许多实例以使你的测试示例彼此隔离。单例模式使这变得困难,并且需要更棘手的方案。

全局变量不好?

它们的确很糟糕,但是你的单例也是一个全局的:整个过程只有一个实例,并且可以从任何地方进行更改。它并不是真正的 Python 全局变量,但它具有所有相同的不良品质,只是单例隐藏在一些棘手的元编程背后。如果你要拥有一个全局变量的代码功能,请提前做好准备

只需要一个对象实例!

那就只创建一个,没有理由通过向其添加单例模式来使类复杂化

可能会创建更多实例!

谁会创建?记录使用类的正确方法。让创建类变得清晰和容易,让使用者以正确的方式去创建,然后顺其自然。你不能防御每一个错误,即使单例也一样

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多