0

我有一些代码可以解决一个名为 nurikabe 的益智游戏,最近我一直在将其重写为 OOP(仍在学习)并具有以下结构:

# CNurikabe.py
from includes import Board, Validation, Heuristics
class CNurikabe(object):
    ...

# CValidation.py
from includes import Board, Heuristics
class CValidation(object):
    ...

# CHeuristics.py
from includes import Board
class CHeuristics(object):
    ...

# CBoard.py
class CBoard(object):
    def __init__(self, filename):
        # Vars shared by every class
        self.x, self.y, self.z, self.t = self.parseData(filename)

# run.py
from CNurikabe import CNurikabe
nurikabe = CNurikabe()
nurikabe.solve('output')

# includes.py
from CBoard import CBoard   
Board = CBoard('data.dat')

from CHeuristics import CHeuristics
Heuristics = CHeuristics()

from CValidation import CValidation
Validation = CValidation()

CBoard 类具有必须在所有其他类之间共享的信息(例如板尺寸、数字坐标等),我也希望它被实例化一次,如果可能的话防止依赖注入(不必要地将文件名传递给每个类的 init 方法, 例如)

需要这些类来访问以下内容:

CValidation 类使用:CBoard 和 CHeuristics

CHeuristics 类使用:CBoard

CNurikabe 类使用:CBoard、CValidation 和 CHeuristics

我拥有的代码按预期工作。我可以按照我想要的方式在其他类中调用其他类的方法,例如:

# CNurikabe.py:
class CNurikabe(object):
    def someFunc(self):
        for i in range(Board.dimensionx):
            Heuristics.doSomeStuff()
            Validation.doSomeMore()

但我可能读过太多关于全局变量如何邪恶的内容。此外,includes.py 中的代码有点骇人听闻,因为如果我更改导入的顺序,程序将无法运行,并抱怨无法导入某些名称。

我还尝试了另一种方法,仅全局实例化 CBoard 类,然后为其他类创建我需要的类的实例。但是我觉得这有点重复,例如,在每个类中创建一个独特的 CHeuristics 全局实例,但这仍然无法解决 CBoard 全局问题。

我还考虑过在每个类的init中创建一个实例,但是代码会非常冗长,例如必须调用: self.Heuristics.doSomeStuff()

所以我的问题是有什么更好的方法来构建它?我读过关于单例模式(这可能有点过分,因为它是一个小项目),以及为多种语言(如 C++ 和 PHP)做这件事的无穷无尽的方法。实际上我这样做的方式类似于“外部类实例”;用 C++ 做的方式,很久以前我在做一个有这种风格的 C++ 项目,我喜欢它,没有看到任何问题,尽管类实例是全局的。

4

1 回答 1

0

全球人是邪恶的。但是,您可能需要一个将一些东西封装在一起的单例模式。我从 C++ 和 Python 获得的经验是,您可以很好地使用语言的混合特性,并使用模块作为单例。(如果你仔细想想,模块变量扮演单例成员变量的角色,模块中的普通函数类似于单例的方法。)

这样,我建议将板功能放入board.py启发式功能heuristic.py中,...,将方法转换为函数,self.variable然后variable使用:

import board
import heuristic
import validation

...

class CNurikabe:     # the explicit (object) base class is not needed in Python 3
    def someFunc(self):
        for i in range(board.dimensionx):
            heuristics.doSomeStuff()
            validation.doSomeMore()

想想import board获取对单例实例的引用——实际上是这样,因为模块对象只有一个实例。它在语法上与您的旧代码相同——除了获取实例(模块)会更容易。

更新:一旦您需要更多实例,您应该再次在课堂上思考。然而,传递对象在 Python 中是非常便宜的操作——您只复制引用值(技术上是地址,即 4 或 8 个字节)。获得参考值后,您可以轻松地将其分配给局部变量。(Python中的每次赋值都意味着复制引用值,从而共享对分配对象的访问。这样,实际上不需要全局变量,也没有借口使用全局变量。

使用局部变量,语法再次保持不变。

于 2013-02-02T09:41:09.783 回答