簡體   English   中英

我如何封裝 class 的私有可變 object,以便它可以通過不可變的 object 公開其屬性?

[英]How can I encapsulate a private mutable object of a class such that it can expose its attributes publicly through an inmutable object?

更具體地說,我正在設計一個 Downloader Class,它的成員變量是對一組 DownloadItem 對象的引用,該對象表示用戶想要通過 .network 下載的資源。 這個想法是下載器 object 將處理有關連接到托管資源的服務器、獲取文件數據/元數據和寫入磁盤的詳細信息,同時在查詢時還會公開 DownloadItems 的 state。

DownloadItem 存儲有關文件的信息,例如文件名、URL、文件大小等,以及其他元數據,例如狀態、進度、下載開始時間等。其中一些信息在實例化之前是未知的,因此 class 本身應該是可變以允許下載器 object 修改它,但只有創建它的下載器 object。

簡而言之,我希望 DownloadItem 的屬性可以通過 Downloader object 訪問,如下所示:

> DownloaderObj = Downloader()
> unique_id = DownloaderObj.download(url='https://path/to/resource', start_inmediate=False)
> print(DownloaderObj._download_queue)
  [<Class: DownloadItem url: https://path/to/resource filesize: -1>]
> DownloaderObj.start_download(unique_id)  # Handler thread updates metadata on the background
> print(DownloaderObj.get_download_by_id(unique_id).filesize)
  1024
> DowloaderObj.get_download_by_id(unique_id).filesize = 1024 # Should raise NotAllowed exception

如果我想稍后擴展 DownloadItem class 以支持其他字段,那么在 Downloader class 中可能有很多樣板代碼公開了這些屬性,但這增加了兩個類之間的耦合並使 class 的可維護性降低。 關於如何實現這一目標的任何想法或想法?

旁注:這個問題主要是為了我自己學習 OOP 模式和設計選擇,所以請隨意批評並盡可能多地添加上下文。

我嘗試做類似的事情:

class InmutableWrapper:
    def __init__(self, obj):
        self._obj = obj

    def __getattr__(self, val):
        return self._obj.__getattr__(val)

然后在調用 Downloader.get_download_by_id() 時返回 InmutableDownloadItemObj = InmutableWrapper(DownloadItemObj) 但我仍然可以進行分配,這將在查詢屬性時反映出來:

> print(Downloader.get_download_by_id(unique_id).filesize)
  1024
> Downloader.get_download_by_id(unique_id).filesize = 2    # Assigment goes through
> print(Downloader.get_download_by_id(unique_id)._obj.filesize) # Underlying object remains unchanged
  1024 
> print(Downloader.get_download_by_id(unique_id).filesize)
  2

實現此目的的一種方法是使用代理模式。 代理模式是一種結構設計模式,它為另一個 object 提供代理或占位符 object 並控制對其的訪問。

在這種情況下,您可以創建一個代理 class 來包裝 DownloadItem object 並公開其屬性。 代理 class 應具有獲取和設置 DownloadItem object 屬性的方法,但不應允許對 DownloadItem object 本身進行任何直接分配。

例如:

class DownloadItemProxy:
    def __init__(self, download_item):
        self._download_item = download_item

    def get_filesize(self):
        return self._download_item.filesize

    def set_filesize(self, filesize):
        self._download_item.filesize = filesize

然后,在 Downloader class 中,您可以返回 DownloadItemProxy class 的實例,而不是 DownloadItem object 本身。 這樣,Downloader class仍然可以訪問和修改DownloadItem object,但是Downloader class的用戶將只能通過代理訪問和修改DownloadItem object的屬性。 希望這有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM