Python的結構型設計模式之外觀模式

書上說:如果某套接字因爲太過於複雜或太專注於底層細節而變得不易使用,那麼可考慮用“外觀模式”將其簡化並統合起來
講真的,後面的享元模式和代理模式還好點,這一個外觀模式,我怎麼看也就是那樣:雖然這次沒有類繼承類,但A方法裏面用B方法,在下面實現B方法。這裏我個人總結的就是這麼回事吶。
此次的例子是設計一套簡單而一致的接口來獲知壓縮文檔裏的各個文件名,並將其解壓。
概括起來就是,定義一個方法類用來解壓一個壓縮文件名,打印包含的文件名,並提供解壓到當前目錄的功能。
class Archive:

    def __init__(self, filename):
        self._name = None
        self._unpack = None
        self._file = None
        self.filename = filename
因此定義的屬性爲 name(文件名),unpack(解壓到當前目錄的對象),file(打開文件的對象),filename 只讀屬性,壓縮文件名。


    @property
    def filename(self):
        return self.__filename

    @filename.setter
    def filename(self, name):
        self.close()
        self.__filename = name

    def close(self):
        if self._file is not None:
            self._file.close()
        self._names = self._unpack = self._file = None

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

    def names(self):
        if self._file is None:
            self._prepare()
        return self._unpack

    def unpack(self):
        if self._file is None:
            self._prepare()
        return self._unpack

    def _prepare(self):
        if self.filename.endswith((".tar.gz", ".tar.bz2", ".tar.xz", ".zip")):
            self._prepare_tarball_or_zip()
        elif self.filename.endswith(".gz"):
            self._prepare_gzip()
        else:
            raise ValueError("unreadable: {}".format(self.filename))
1.打開文件了肯定要關閉
2.獲取壓縮包內的文件名
3.解壓壓縮包
4.爲實現具體功能提供統一方法

    def _prepare_tarball_or_zip(self):
        def safe_extractall():
            unsafe = []
            for name in self.names():
                if not self.is_safe(name):
                    unsafe.append(name)
            if unsafe:
                raise ValueError("unsafe to unpack: {}".format(unsafe))
            self._file.extractall()
        if self.filename.endswith(".zip"):
            self._file = zipfile.ZipFile(self.filename)
            self._names = self._file.namelist
            self._unpack = safe_extractall
        else:
            suffix = os.path.splitext(self.filename)[1]
            self._file = tarfile.open(self.filename, "r" + suffix[1:])
            self._names = self._file.getnames
            self._unpack = safe_extractall

    def is_safe(self, filename):
        return not (filename.startswith(("/", "\\")) or (len(filename) > 1 and filename[1] == ":" and
                                                         filename[0] in string.ascii_letter) or
                    re.search(r"[.][.][/\\]", filename))

    def _prepare_gzip(self):
        self._file = gzip.open(self.filename)
        filename = self.filename[:-3]
        self._names = lambda :[filename]
        def extractall():
            with open(filename, "wb") as file:
                file.write(self._file.read())
        self._unpack = extractall
這是實現解壓功能。都是方法裏面再定義一個方法 extracall 完成其本身的價值。


這裏的關鍵是,對於不同的壓縮文檔,你可以使用一個 _prepare 方法來完成。因此對於要是有更多的文件類型,只需要在 _prepare 裏面添加即可。

發佈了235 篇原創文章 · 獲贊 27 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章