結構型模式 ------ 設計模式第4章

1. 適配器模式

      將一個類的接口轉換成客戶希望的另外一個接口,適配器使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。實現適配器的兩種方式,類適配器使用多繼承,對象適配器使用組合組合就是一個類中放入另一類的對象。 先來看下組合:

class A:
	pass
	
class B:
	def __init__():
		self.a = A()

類適配器模式使用示例:

# 類適配器模式使用示例:
from abc import ABCMeta, abstractmethod

# 目標接口
class Payment(object, metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

class Alipay(Payment):
    def pay(self, money):
        print('支付了%d' % money)

# 待適配的類
class BankPay():
    def cost(self, money):
        print('銀聯支付了%d' % money)

# 類適配器
class PaymentAdapter(Payment, BankPay):
    """
    把不兼容cost轉換成pay
    """

    def pay(self, money):
        self.cost(money)

p = PaymentAdapter()
p.pay(100)
"""
銀聯支付了100
"""

對象適配器模式使用示例:

# 類適配器模式使用示例:
from abc import ABCMeta, abstractmethod

# 目標接口
class Payment(object, metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass

class Alipay(Payment):
    def pay(self, money):
        print('支付了%d' % money)

# 待適配的類
class BankPay():
    def cost(self, money):
        print('銀聯支付了%d' % money)

# 待適配的類
class ApplePay():
    def cost(self, money):
        print('蘋果支付了%d' % money)

# 對象適配器
class PaymentAdapter(Payment):
    def __init__(self, payment):
        self.payment = payment

    def pay(self, money):
        self.payment.cost(money)

p = PaymentAdapter(ApplePay())
p.pay(100)
p = PaymentAdapter(BankPay())
p.pay(100)
"""
蘋果支付了100
銀聯支付了100
"""

      適配器模式有三種角色,分別是目標接口、待適配的類和適配器。適用場景是:想使用一個已存在的類,而它的接口不符合你的要求。想使用一些已經存在的類,但是不可能對每一個都進行子類化以匹配它們的接口。對象適配器可以適配它的父類接口。

2. 橋模式

      橋模式是將一個事物的兩個維度分離,使其都可以獨立地變化。當事物有兩個維度的表現,兩個維度都可能擴展時使用。優點是:抽象和實現相分離,擴展能力強。如果不使用橋模式,在任何維度進行擴展,需要改好多代碼,因爲使用到了繼承:

class Shape:
	pass

class Rectangle(Shape):
	pass

class Circle(Shape):
	pass

class RedRectangle(Rectangle):
	pass

class GreenRectangle(Rectangle):
	pass
	
class RedCircle(Circle):
	pass

class GreenCircle(Circle):
	pass

      以上代碼形狀和顏色兩個維度是通過類的繼承關係緊密結合在一起,是緊耦合。緊耦合是是不可取的,應用橋模式的思想,可以使用組合來實現(鬆耦合)。如果需要畫直線,直接加上直線的類。需要新顏色,直接加上顏色的類。兩個維度都可以自由擴展,不需要添加很多代碼。這裏的角色有抽象、細化抽象、實現者和具體實現者:

from abc import ABCMeta, abstractmethod

# 抽象
class Shape(metaclass=ABCMeta):
    def __init__(self, color):
        self.color = color

    @abstractmethod
    def draw(self):
        pass

# 實現
class Color(metaclass=ABCMeta):
    @abstractmethod
    def paint(self, shape):
        pass

# 細化抽象
class Rectangle(Shape):
    name = '長方形'

    def draw(self):
        self.color.paint(self)

# 如果要擴展形狀,只需要添加形狀類
class Circle(Shape):
    name = '圓形'

    def draw(self):
        self.color.paint(self)

# 細化實現
class Red(Color):
    def paint(self, shape):
        print('畫紅色的%s' % shape.name)

# 如果要擴展顏色,只需要添加顏色類
class Green(Color):
    def paint(self, shape):
        print('畫綠色的%s' % shape.name)

rectangle = Rectangle(Red())
rectangle.draw()
circle = Circle(Green())
circle.draw()
"""
畫紅色的長方形
畫綠色的圓形
"""
3. 組合模式

      將對象組合成樹形結構以表示“部分-整體”的層次結構(特別是結構是遞歸的),組合模式使得用戶對單個對象和組合對象的使用具有一致性。優點是定義了包含基本對象和組合對象的層次結構;簡化客戶端代碼,客戶端可以一致地使用組合對象和單個對象;更加容易增加新類型的組件。

from abc import ABCMeta, abstractmethod

# 抽象組件
class Graphic(metaclass=ABCMeta):
    @abstractmethod
    def draw(self):
        pass

# 葉子組件
class Point(Graphic):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return '點(%s,%s)' % (self.x, self.y)

    def draw(self):
        print(self)

# 葉子組件
class Line(Graphic):
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def __str__(self):
        return '線段[(%s,%s)]' % (self.p1, self.p2)

    def draw(self):
        print(self)

# 複合組件
class Picture(Graphic):
    def __init__(self, iterable):
        self.children = []
        for g in iterable:
            self.add(g)

    def add(self, graphic):
        self.children.append(graphic)

    def draw(self):
        for g in self.children:
            g.draw()

# 簡單圖形
print('------簡單圖形------')
p = Point(1, 2)
l1 = Line(Point(1, 2), Point(3, 4))
l2 = Line(Point(5, 6), Point(7, 8))
print(p)
print(l1)
print(l2)
print('------複合圖形(p,l1,l2)------')
# 複合圖形
pic = Picture([p, l1, l2])
pic.draw()
4. 外觀模式

      外觀模式爲子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層的接口,這個接口使得這一子系統更加容易使用。外觀模式下的角色有外觀和子系統類,優點是:減少系統相互依賴,提高靈活性,提高了安全性。下面看一個例子:

# 子系統類
class CPU:
    def run(self):
        print('CPU start to run...')

    def stop(self):
        print('CPU stop to run...')

# 子系統類
class Disk:
    def run(self):
        print('Disk start to run...')

    def stop(self):
        print('Disk stop to run...')

# 子系統類
class Memory:
    def run(self):
        print('Memory start to run...')

    def stop(self):
        print('Memory stop to run...')

# 外觀
class Computer():
    def __init__(self):
        self.CPU = CPU()
        self.Disc = Disk()
        self.Member = Memory()

    def run(self):
        self.CPU.run()
        self.Disc.run()
        self.Member.run()

    def stop(self):
        self.CPU.stop()
        self.Disc.stop()
        self.Member.stop()

# 客戶端,高層代碼
c = Computer()
c.run()
c.stop()
5. 代理模式

      爲其它對象提供一種代理以控制對這個對象的訪問。角色有抽象實體、實體和代理。應用場景有遠程代理:爲遠程的對象提供代理(通過ORM向數據庫寫值,不用關注數據庫是在遠程);虛代理:根據需要創建很大的對象(需要的時候創建對象);保護代理:控制對原始對象的訪問,用於對象有不同的訪問權限。下面是不使用虛代理的例子:

from abc import ABCMeta, abstractmethod

class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):
        pass

    @abstractmethod
    def set_content(self, content):
        pass

class RealSubject(Subject):
    def __init__(self, filename):
        self.filename = filename
        print('讀取文件內容!')
        with open(self.filename, 'r', encoding='utf-8') as f:
            self.content = f.read()

    def get_content(self):
        return self.content

    def set_content(self, content):
        with open(self.filename, 'w', encoding='utf-8') as f:
            f.write(content)

subj = RealSubject('test.txt')
"""
讀取文件內容!
"""

使用虛代理的例子:

from abc import ABCMeta, abstractmethod

class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):
        pass

    @abstractmethod
    def set_content(self, content):
        pass

class RealSubject(Subject):
    def __init__(self, filename):
        self.filename = filename
        print('讀取文件內容!')
        with open(self.filename, 'r', encoding='utf-8') as f:
            self.content = f.read()

    def get_content(self):
        return self.content

    def set_content(self, content):
        with open(self.filename, 'w', encoding='utf-8') as f:
            f.write(content)

class VirtualProxy(Subject):
    def __init__(self, filename):
        self.filename = filename
        self.subj = None

    def get_content(self):
        if not self.subj:
            self.subj = RealSubject(self.filename)
        return self.subj.get_content()

    def set_content(self, content):
        if not self.subj:
            self.subj = RealSubject(self.filename)

        return self.subj.set_content(content)

subj = VirtualProxy('test.txt')
print(subj.get_content())
"""
讀取文件內容!
"""

      不使用虛代理,只要是實例化 RealSubject 類,就會讀取這個文件佔用內存。使用虛代理後,可以和根據需要創建對象,用戶不調用是不會創建 RealSubject 對象的,節省了內存的開銷。如果需要只有讀的權限而沒有寫的權限,可以使用保護代理:

from abc import ABCMeta, abstractmethod

class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):
        pass

    @abstractmethod
    def set_content(self, content):
        pass

class RealSubject(Subject):
    def __init__(self, filename):
        self.filename = filename
        print('讀取文件內容!')
        with open(self.filename, 'r', encoding='utf-8') as f:
            self.content = f.read()

    def get_content(self):
        return self.content

    def set_content(self, content):
        with open(self.filename, 'w', encoding='utf-8') as f:
            f.write(content)

class ProtectedSubject(Subject):
    def __init__(self, filename):
        self.subj = RealSubject(filename)

    def get_content(self):
        return self.subj.get_content()

    def set_content(self, content):
        raise PermissionError('無寫入權限!')

subj = ProtectedSubject('test.txt')
print(subj.get_content())
subj.set_content('abc')
"""
讀取文件內容!
test file!
Traceback (most recent call last):
  File "/home/thanlon/projects/PycharmProjects/untitled/代理模式.py", line 42, in <module>
    subj.set_content('abc')
  File "/home/thanlon/projects/PycharmProjects/untitled/代理模式.py", line 37, in set_content
    raise PermissionError('無寫入權限!')
PermissionError: 無寫入權限!
"""
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章