13.适配模式

定义

  • 将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
  • 适配模式的作用:
    • 接口转换,将原有的接口(或方法)转换成另一种接口。
    • 用新的接口包装一个已有的类。
    • 匹配一个老的组件到一个新的接口。
  • 又叫变压器模式,也叫包装模式(Wrapper)

适配模式的模型抽象

代码框架

from abc import ABCMeta, abstractmethod  
  
  
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法  
  
class Target(metaclass=ABCMeta):  
    """目标类"""  
  
    @abstractmethod  
    def function(self):  
        pass  
  
  
class Adaptee:  
    """源对象类"""  
  
    def speciaficFunction(self):  
        print("被适配对象的特殊功能")  
  
  
class Adapter(Target):  
    """适配器"""  
  
    def __init__(self, adaptee):  
        self.__adaptee = adaptee  
  
    def function(self):  
        print("进行功能的转换")  
        self.__adaptee.speciaficFunction()

类图

  • 适配模式的实现有两种方式:一种是组合方式,另一种是继承方式
    • 组合方式(代码框架中的是这种)
    • 继承方式
  • 适配模式的两种实现方式,比较推荐组合的方式,因为在一些没有 interface 类型的编程语言(如 C++、Python)中,Adapter 类就会多继承,同时继承 Target 和 Adaptee,在程序设计中应该尽量避免多继承(虽然 Target 只是一个接口类)。

模型说明

  • 适配模式中主要有三个角色,在设计适配模式时要找到并区分这些角色。
    • 目标(Target):即你期望的目标接口,要转换成的接口。
    • 源对象(Adaptee):即要被转换的角色,要把谁转换成目标角色。
    • 适配器(Adapter):适配模式的核心角色,负责把源对象转换和包装成目标对象。
  • 优缺点
    • 优点:
      • 可以让两个没有关联的类一起运行,起中间转换的作用。
      • 提高了类的复用率。
      • 灵活性好,不会破坏原有系统。
    • 缺点:
      • 如果原有系统没有设计好(如 Target 不是抽象类或接口,而是一个实体类),适配模式将很难实现。
      • 过多地使用适配器,容易使代码结构混乱,如明明看到调用的是 A 接口,内部调用的却是 B 接口的实现。

例子

from abc import ABCMeta, abstractmethod  
# 引入ABCMeta和abstractmethod来定义抽象类和抽象方法  
import os  
  
  
# 导入os库,用于文件、路径相关的解析  
  
class Page:  
    """电子书一页的内容"""  
  
    def __init__(self, pageNum):  
        self.__pageNum = pageNum  
  
    def getContent(self):  
        return "第 " + str(self.__pageNum) + " 页的内容..."  
  
  
class Catalogue:  
    """目录结构"""  
  
    def __init__(self, title):  
        self.__title = title  
        self.__chapters = []  
  
    def addChapter(self, title):  
        self.__chapters.append(title)  
  
    def showInfo(self):  
        print("书名:" + self.__title)  
        print("目录:")  
        for chapter in self.__chapters:  
            print("    " + chapter)  
  
  
class IBook(metaclass=ABCMeta):  
    """电子书文档的接口类"""  
  
    @abstractmethod  
    def parseFile(self, filePath):  
        """解析文档"""  
        pass  
  
    @abstractmethod  
    def getCatalogue(self):  
        """获取目录"""  
        pass  
  
    @abstractmethod  
    def getPageCount(self):  
        """获取页数"""  
        pass  
  
    @abstractmethod  
    def getPage(self, pageNum):  
        """获取第pageNum页的内容"""  
        pass  
  
  
class TxtBook(IBook):  
    """TXT解析类"""  
  
    def parseFile(self, filePath):  
        # 模拟文档的解析  
        print(filePath + " 文件解析成功")  
        self.__title = os.path.splitext(filePath)[0]  
        self.__pageCount = 500  
        return True  
  
    def getCatalogue(self):  
        catalogue = Catalogue(self.__title)  
        catalogue.addChapter("第一章 标题")  
        catalogue.addChapter("第二章 标题")  
        return catalogue  
  
    def getPageCount(self):  
        return self.__pageCount  
  
    def getPage(self, pageNum):  
        return Page(pageNum)  
  
  
class EpubBook(IBook):  
    """Epub解析类"""  
  
    def parseFile(self, filePath):  
        # 模拟文档的解析  
        print(filePath + " 文件解析成功")  
        self.__title = os.path.splitext(filePath)[0]  
        self.__pageCount = 800  
        return True  
  
    def getCatalogue(self):  
        catalogue = Catalogue(self.__title)  
        catalogue.addChapter("第一章 标题")  
        catalogue.addChapter("第二章 标题")  
        return catalogue  
  
    def getPageCount(self):  
        return self.__pageCount  
  
    def getPage(self, pageNum):  
        return Page(pageNum)  
  
  
class Outline:  
    """第三方PDF解析库的目录类"""  
  
    def __init__(self):  
        self.__outlines = []  
  
    def addOutline(self, title):  
        self.__outlines.append(title)  
  
    def getOutlines(self):  
        return self.__outlines  
  
  
class PdfPage:  
    """PDF页"""  
  
    def __init__(self, pageNum):  
        self.__pageNum = pageNum  
  
    def getPageNum(self):  
        return self.__pageNum  
  
  
class ThirdPdf:  
    """第三方PDF解析库"""  
  
    def __init__(self):  
        self.__pageSize = 0  
        self.__title = ""  
  
    def open(self, filePath):  
        print("第三方库解析PDF文件:" + filePath)  
        self.__title = os.path.splitext(filePath)[0]  
        self.__pageSize = 1000  
        return True  
  
    def getTitle(self):  
        return self.__title  
  
    def getOutline(self):  
        outline = Outline()  
        outline.addOutline("第一章 PDF电子书标题")  
        outline.addOutline("第二章 PDF电子书标题")  
        return outline  
  
    def pageSize(self):  
        return self.__pageSize  
  
    def page(self, index):  
        return PdfPage(index)  
  
  
class PdfAdapterBook(IBook):  
    """对第三方的PDF解析库重新进行包装"""  
  
    def __init__(self, thirdPdf):  
        self.__thirdPdf = thirdPdf  
  
    def parseFile(self, filePath):  
        # 模拟文档的解析  
        rtn = self.__thirdPdf.open(filePath)  
        if rtn:  
            print(filePath + "文件解析成功")  
        return rtn  
  
    def getCatalogue(self):  
        outline = self.__thirdPdf.getOutline()  
        print("将Outline结构的目录转换成Catalogue结构的目录")  
        catalogue = Catalogue(self.__thirdPdf.getTitle())  
        for title in outline.getOutlines():  
            catalogue.addChapter(title)  
        return catalogue  
  
    def getPageCount(self):  
        return self.__thirdPdf.pageSize()  
  
    def getPage(self, pageNum):  
        page = self.__thirdPdf.page(pageNum)  
        print("将PdfPage的面对象转换成Page的对象")  
        return Page(page.getPageNum())  
  
  
class Reader:  
    """阅读器"""  
  
    def __init__(self, name):  
        self.__name = name  
        self.__filePath = ""  
        self.__curBook = None  
        self.__curPageNum = -1  
  
    def __initBook(self, filePath):  
        self.__filePath = filePath  
        extName = os.path.splitext(filePath)[1]  
        if extName.lower() == ".epub":  
            self.__curBook = EpubBook()  
        elif extName.lower() == ".txt":  
            self.__curBook = TxtBook()  
        elif extName.lower() == ".pdf":  
            self.__curBook = PdfAdapterBook(ThirdPdf())  
        else:  
            self.__curBook = None  
  
    def openFile(self, filePath):  
        self.__initBook(filePath)  
        if self.__curBook is not None:  
            rtn = self.__curBook.parseFile(filePath)  
            if rtn:  
                self.__curPageNum = 1  
            return rtn  
        return False  
  
    def closeFile(self):  
        print("关闭 " + self.__filePath + " 文件")  
        return True  
  
    def showCatalogue(self):  
        catalogue = self.__curBook.getCatalogue()  
        catalogue.showInfo()  
  
    def prePage(self):  
        print("往前翻一页:", end="")  
        return self.gotoPage(self.__curPageNum - 1)  
  
    def nextPage(self):  
        print("往后翻一页:", end="")  
        return self.gotoPage(self.__curPageNum + 1)  
  
    def gotoPage(self, pageNum):  
        if 1 < pageNum < self.__curBook.getPageCount() - 1:  
            self.__curPageNum = pageNum  
  
        print("显示第" + str(self.__curPageNum) + "页")  
        page = self.__curBook.getPage(self.__curPageNum)  
        page.getContent()  
        return page  
  
  
# Test  
# =======================================================================================================================  
  
  
def testReader():  
    reader = Reader("阅读器")  
    if not reader.openFile("平凡的世界.txt"):  
        return  
    reader.showCatalogue()  
    reader.prePage()  
    reader.nextPage()  
    reader.nextPage()  
    reader.closeFile()  
    print()  
  
    if not reader.openFile("追风筝的人.epub"):  
        return  
    reader.showCatalogue()  
    reader.nextPage()  
    reader.nextPage()  
    reader.prePage()  
    reader.closeFile()  
    print()  
  
    if not reader.openFile("如何从生活中领悟设计模式.pdf"):  
        return  
    reader.showCatalogue()  
    reader.nextPage()  
    reader.nextPage()  
    reader.closeFile()  
  
  
testReader()

应用场景

  • 系统需要使用现有的类,而这些类的接口不符合现有系统的要求。
  • 对已有的系统拓展新功能,尤其适用于在设计良好的系统框架下增加接入第三方的接口或第三方的 SDK。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇