我有以下基类:
class ClientRepo(Repository):
def __init__(self) -> None:
self.__clientList = []
def hasClientWithId(self, clientId):
for client in self.__clientList:
if client.getId() == clientId:
return True
return False
def addClient(self, client):
if type(client).__name__ == 'ClientDAO':
if not self.hasClientWithId(client.getId()):
client.setClientId(self.__maximumIndexInClientList() + 1)
self.__clientList.append(client)
else:
raise ObjectAlreadyInCollectionException
else:
raise TypeError
基本上只保存一个列表,并且可以向其中添加ClientDAO。
以及从中得出的以下内容:
class ClientFileRepository(ClientRepo):
def __init__(self, fileName) -> None:
super().__init__()
self.__fileName = fileName
self.__file = None
def hasClientWithId(self, clientId):
self.__loadRepo()
hasClientWithId = super().hasClientWithId(clientId)
super().clean()
return hasClientWithId
def addClient(self, client):
self.__loadRepo()
super().addClient(client)
self.__storeRepo()
super().clean()
def __loadFileReadMode(self):
self.__file = open(self.__fileName, "r")
def __loadFileWriteMode(self):
self.__file = open(self.__fileName, "w")
def __closeFile(self):
self.__file.close()
def __loadRepo(self):
self.__loadFileReadMode()
for line in self.__file:
splitLine = line.split()
clientToAdd = ClientDAO(splitLine[1])
clientToAdd.setClientId(int(splitLine[0]))
super().addClientWithId(clientToAdd)
self.__closeFile()
def __storeRepo(self):
self.__loadFileWriteMode()
self.__file.write("")
for client in super().getList():
self.__file.write(self.clientToString(client))
self.__closeFile()
def clientToString(self, clientDAO):
return str(clientDAO.getId()) + " " + clientDAO.getName() + "\n"
一个类,该类应从文件加载列表,从父级调用addClient
,并将更新后的列表存储在文件中。问题在于,子类将文件加载到addClient
中之后,它将调用父级中的方法,该方法再次从子级中调用hasClientWithId
。但是我希望它从父级那里调用hasClientWithId
,即它所在的上下文。我可以实现吗?
答案 0 :(得分:1)
我可以想到几种实现目标的方法。我对它们的排名从最坏到最好
1。确实是您要的
您希望ClientRepo.addClient
呼叫ClientRepo.hasClientWithId
而不是ClientFileRepository.hasClientWithId
。可以强制执行以下操作:
class ClientRepo(Repository):
def addClient(self, client):
if type(client).__name__ == 'ClientDAO':
if not ClientRepo.hasClientWithId(self, client.getId()):
client.setClientId(self.__maximumIndexInClientList() + 1)
self.__clientList.append(client)
else:
raise ObjectAlreadyInCollectionException
else:
raise TypeError
这不是一个好方法,因为它不直观并且破坏了OOP的原理。任何其他编写覆盖ClientRepo
的{{1}}子类的程序员都希望,即使在hasClientWithId
内,每次调用hasClientWithId
也会有影响
2。让addClient
决定使用哪个功能
添加变量
ClientFileRepository
在self.__isFileOpen = False
中,在打开文件时将其设置为ClientFileRepository.__init__
,在关闭文件时将其设置为True
。然后将False
中的hasClientWithId
更改为
ClientFileRepository
,以避免再次打开同一文件。这行得通,但是为此类编写新函数非常困难,因为您始终需要知道函数调用是来自类内部还是其他地方的调用。同样,这似乎效率很低,因为即使只添加一个客户端,您也会读写整个文件。
3。仅读取一次文件,然后修改基础的def hasClientWithId(self, clientId):
if not self.__isFileOpen:
self.__loadRepo()
result = super().hasClientWithId(clientId)
super().clean()
return result
else:
return super().hasClientWithId(clientId)
ClientRepo
这显然是假设在调用class ClientFileRepository(ClientRepo):
def __init__(self, fileName) -> None:
super().__init__()
self.__fileName = fileName
self.__loadRepo()
# No hasClientWithId needed
def addClient(self, client):
super().addClient(client)
self.__storeRepo()
def __loadRepo(self):
with open(self.__filename) as file:
for line in file:
splitLine = line.split()
clientToAdd = ClientDAO(splitLine[1])
clientToAdd.setClientId(int(splitLine[0]))
super().addClientWithId(clientToAdd)
def __storeRepo(self):
with open(self.__filename, "w") as file:
file.write("")
for client in super().getList():
file.write(self.clientToString(client))
之间文件没有被其他人更改,并且程序仍然为每个addClient
覆盖了整个文件。如果这对您来说是个问题,则最好明确地公开addClient
和loadRepo
。然后,使用此类的程序员可以决定何时进行加载和保存是必要且有用的。您可以为此使用上下文管理器。
其他:阅读并保存每种方法的文件
您可以使用函数修饰符来使用解决方案2,而无需为每个函数编写相同的代码:
storeRepo
在这里要小心,使用它不是很直观。例如,import functools
def loadAndStore(function):
@functoools.wraps(function)
def wrappedFunction(self, *args, **kwargs):
if self.__isFileOpen:
return function(self, *args, **kwargs)
else:
self.__isFileOpen = True
self.__loadRepo()
try:
return function(self, *args, **kwargs)
except Exception as e: # Only catch expected exceptions
raise
finally:
self.__storeRepo()
self.clear() # some cleanup
self.__isFileOpen = False
return wrappedFunction
class ClientFileRepository(ClientRepo):
def __init__(self, fileName) -> None:
super().__init__()
self.__fileName = fileName
self.__isFileOpen = False
@loadAndStore
def hasClientWithId(self, clientId):
return super().hasClientWithId(clientId)
@loadAndStore
def addClient(self, client):
super().addClient(client)
def __loadRepo(self):
with open(self.__filename) as file:
for line in file:
splitLine = line.split()
clientToAdd = ClientDAO(splitLine[1])
clientToAdd.setClientId(int(splitLine[0]))
super().addClientWithId(clientToAdd)
def __storeRepo(self):
with open(self.__filename, "w") as file:
file.write("")
for client in super().getList():
file.write(self.clientToString(client))
是在self.__isFileOpen
中定义的,但是下面的方法都没有直接使用它。相反,它的使用隐藏在__init__
装饰器中。
最后一些快速提示:
loadAndStore
是错误的做法。使用type(client).__name__ == 'ClientDAO'
完全采用OOP isinstance(client, ClientDAO)
之类的私有变量,只需在变量前面加上一个下划线即可表示“内部使用”。函数也是如此。