适配模式
适配器模式
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
适配器模式的作用:
- 接口转换,将原有的接口(或方法)转换成另一种接口;
- 用新的接口包装一个已有的类;
- 匹配一个老的组件到一个新的接口。
设计思想
适配器模式又叫变压器模式,也叫包装模式(Wrapper),它的核心思想是将一个对象经过包装或转换后使它符合指定的接口,使得调用方可以像使用这接口的一般对象一样使用它。这一思想,在我们生活中可谓是处处可见,比如变压器插座,能让你像使用国内电器一样使用美标(110V)电器;还有就是各种转接头,如 MiniDP 转 HDMI 转接头、HDMI 转 VGA 线转换器、Micro USB 转 Type-C 转接头等。
适配器模式的类图如下:
Target 是一个接口类,是提供给用户调用的接口抽象,如上面示例中的 IHightPerson。Adaptee 是你要进行适配的对象类,如上面的 ShortPerson。Adapter 是一个适配器,是对 Adaptee 的适配,它将 Adaptee 的对象转换(或说包装)成符合 Target 接口的对象;如上面的 DecoratePerson,将 ShortPerson 的 getRealHeight 和 getShoesHeight 方法包装成 IHightPerson 的 getHeight 接口。
模型说明
设计要点
适配器模式中主要三个角色,在设计适配器模式时要找到并区分这些角色:
- 目标(Target): 即你期望的目标接口,要转换成的接口。
- 源对象(Adaptee): 即要被转换的角色,要把谁转换成目标角色。
- 适配器(Adapter): 适配器模式的核心角色,负责把源对象转换和包装成目标对象。
优缺点
适配器模式的优点
- 可以让两个没有关联的类一起运行,起着中间转换的作用。
- 提高了类的复用。
- 灵活性好,不会破坏原有的系统。
适配器模式的缺点
- 如果原有系统没有设计好(如 Target 不是抽象类或接口,而一个实体类),适配器模式将很难实现。
- 过多地使用适配器,容易使代码结构混乱,如明明看到调用的是 A 接口,内部调用的却是 B 接口的实现。
class Page: """ 电子书一页的内容 """ def __init__(self,pageNum): self.__pageNum = pageNum def getCountent(self): return "第"+str(self.__pageNum)+"页内容...." class CateLogue: """ 目录结构 """ def __init__(self,title): self.__title = title self.__chapters = [] self.setChapter("第一章") self.setChapter("第二章") def setChapter(self,title): self.__chapters.append(title) def showInfo(self): print("标题"+self.__title) for chapter in self.__chapters: print(chapter) class IBook: """ 电子书文档的接口类 """ def parseFile(self,filePath): pass def getCatalogue(self): pass def getCount(self): pass def getPage(self,pageNum): pass class TxtBook(IBook): """ TXT解析器 """ def parseFile(self,filePath): print(filePath+"文件解析成功") self.__pageCount = 500 return True def getCatalogue(self): return CateLogue("TXT电子书") def getPageCount(self): return self.__pageCount def getPage(self,pageNum): return Page(pageNum) class EpubBook(IBook): """ EPUB解析器 """ def parseFile(self,filePath): #模拟文档的解析 print(filePath+"文件解析成功") self.__pageCount = 800 return True def getCatalogue(self): return CateLogue("Epub电子书") def getPageCount(self): return self.__pageCount def getPage(self, pageNum): return Page(pageNum) class OutLine: """ 第三方PDF解析库的目录类 """ pass 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 def open(self,filePath): print("第三方解析PDF文件:"+filePath) self.__pageSize = 1000 return True def getOutline(self): return OutLine() def pageSize(self): return self.__pageSize def page(self,index): return PdfPage(index) class PdfAdaterBook(ThirdPdf,IBook): """ PDF解析类 """ def parseFile(self,filePath): rtn = super().open(filePath) if(rtn): print(filePath+"解析文件成功") return rtn def getCatalogue(self): outline = super().getOutline() print("将Outline结构的目录转换成Catalogue结构的目录") return CateLogue("PDF电子书") def getPageCount(self): return super().pageSize() def getPage(self,pageNum): page = self.page(pageNum) print("将PdfPage的对象转换成Page的对象") return Page(page.getPageNum()) import os 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 = PdfAdaterBook() 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): return self.gotoPage(self.__curPageNum - 1) def nexPage(self): return self.gotoPage(self.__curPageNum + 1) def gotoPage(self,pageNum): if pageNum<1 or pageNum>self.__curBook.getPageCount(): return None self.__curPageNum = pageNum print("显示第"+str(self.__curPageNum)+"页") page = self.__curBook.getPage(self.__curPageNum) page.getCountent() return page if __name__ == '__main__': reader = Reader("阅读器") if not reader.openFile("平凡的世界.txt"): pass reader.showCatalogue() reader.gotoPage(1) reader.nexPage() reader.closeFile() print() if not reader.openFile("平凡的世界.epub"): pass reader.showCatalogue() reader.gotoPage(5) reader.nexPage() reader.closeFile() print() if not reader.openFile("平凡的世界.pdf"): pass reader.showCatalogue() reader.gotoPage(10) reader.nexPage() reader.closeFile()