设计模式之结构型模式

在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。对象结构的设计很容易体现出设计人员水平的高低,这里有7个具体的结构型模式可供研究,它们分别是:

  1. 外观模式(Facade)
  2. 适配器模式(Adapter)
  3. 代理模式(Proxy)
  4. 装饰模式(Decorator)
  5. 桥模式(Bridge)
  6. 组合模式(Composite)
  7. 享元模式(Flyweight)

外观模式

外观模式(Facade),他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口。这种类型的设计模式属于结构性模式。为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用。 简单来说,该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用。这个模式中,设计到3个角色:

  • 门面角色:外观模式的核心。它被客户角色调用,它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合
  • 子系统角色:实现了子系统的功能。它对客户角色和Facade时未知的。它内部可以有系统内的相互交互,也可以由供外界直接调用的接口
  • 客户角色:通过调用Facede来完成要实现的功能

################ 各个子系统 ##############
class Stock():
    name = '股票1'

    def buy(self):
        print('买 ' + self.name)

    def sell(self):
        print('卖 ' + self.name)

class ETF():
    name = '指数型基金'

    def buy(self):
        print('买 ' + self.name)

    def sell(self):
        print('卖 ' + self.name)

class Future():
    name = '期货'

    def buy(self):
        print('买 ' + self.name)

    def sell(self):
        print('卖 ' + self.name)

class NationDebt():
    name = '国债'

    def buy(self):
        print('买 ' + self.name)

    def sell(self):
        print('卖 ' + self.name)

class Option():
    name = '权证'

    def buy(self):
        print('买 ' + self.name)

    def sell(self):
        print('卖 ' + self.name)

###################### 门面 ########################
class Fund():
    def __init__(self):
        self.stock = Stock()
        self.etf = ETF()
        self.future = Future()
        self.debt = NationDebt()
        self.option = Option()

    def buyFund(self):
        self.stock.buy()
        self.etf.buy()
        self.debt.buy()
        self.future.buy()
        self.option.buy()

    def sellFund(self):
        self.stock.sell()
        self.etf.sell()
        self.future.sell()
        self.debt.sell()
        self.option.sell()


if __name__ == '__main__':
    myFund = Fund()
    myFund.buyFund()
    myFund.sellFund()

适配器模式

将一个类的接口转换成客户希望的另一个接口。适配器模式使得原来由于接口不兼容而不能一起工作的那些类可以一起工作
组成部分:

  1. 目标接口(Target)
  2. 待适配的类(Adaptee)
  3. 适配器(Adapter)

根据实现的不同,共分为两种适配器

  1. 类适配器:使用多继承
  2. 对象适配器:使用组合
from  abc import abstractmethod,ABCMeta
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        raise NotImplementedError

class Alipay(Payment):
    def pay(self, money):
        print("支付宝支付%s元"%money)


class ApplePay(Payment):
    def pay(self, money):
        print("苹果支付%s元"%money)

# =========待适配类==========
class WechatPay:
    def huaqian(self,a,b):
        print("微信支付%s元" % (a + b))

######### 类适配器 ##############
class AdapterPay(Payment, WechatPay):
    def pay(self, money):
        self.huaqian(money, 0)

################ 对象适配器  ##################

class AdapterPay:
    def __init__(self, payment):
        self.payment = payment
    def pay(self, money):
        self.payment.huaqian(money, 0)

桥接模式

生活中的一个例子:
就拿汽车在路上行驶的来说。即有小汽车又有公共汽车,它们都不但能在市区中的公路上行驶,也能在高速公路上行驶。这你会发现,对于交通工具(汽车)有不同的类型,然而它们所行驶的环境(路)也在变化,在软件系统中就要适应两个方面的变化?怎样实现才能应对这种变化呢?
概述: 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度?这就要使用Bridge模式。
意图: 把抽象部分与实现部分分离,使它们都可以独立的变化。

################ Abstraction 定义抽象接口;拥有一个Impl类型对象引用,在这里Impl类型对象引用是car  ######
class AbstractRoad(object):
    '''公路基类'''
    car = None

############## ComcreteImplementor 实现Implementor接口,给出具体实现;####################
class Street(AbstractRoad):
    '''市区街道'''
    def run(self):
        self.car.run()
        print("在市区街道上行驶")


class SpeedWay(AbstractRoad):
    '''高速公路'''

    def run(self):
        self.car.run()
        print("在高速公路上行驶")

############# Implementor Implementor是具体实现的接口#############
class AbstractCar(object):
    '''车辆基类'''
    def run(self):
        pass

class Car(AbstractCar):
    '''小汽车'''

    def run(self):
        print("小汽车在")


class Bus(AbstractCar):
    '''公共汽车'''
    road = None

    def run(self):
        print("公共汽车在")

############## 加上人 ##################
class People(object):
    road = None
# 加上人
class Man(People):
    def drive(self):
        print("男人开着")
        self.road.run()


# 加上人
class Woman(People):
    def drive(self):
        print("女人开着")
        self.road.run()


if __name__ == "__main__":
    # 小汽车在高速上行驶
    road1 = SpeedWay()
    road1.car = Car()
    road1.run()

    #
    road2 = SpeedWay()
    road2.car = Bus()
    road2.run()

    # 人开车
    road3 = Street()
    road3.car = Car()

    p1 = Man()
    p1.road = road3
    p1.drive()

桥接模式本质上利用的是面向对象的组合

组合模式

将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性.
当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了.

组成部分:抽象组件;叶子组件;复合组件

适用场景:表示对象的‘部分-整体’层次结构(特别是结构是递归的);希望用户忽略组合对象与单个对象的不同,用户统一的使用组合结构中的所有对象

from abc import ABCMeta, abstractclassmethod

################## 抽象组件  ####################
class Store(metaclass=ABCMeta):
    # 添加店面
    @abstractclassmethod
    def add(self, store):
        pass

    # 删除店面
    @abstractclassmethod
    def remove(self, store):
        pass

    @abstractclassmethod
    def pay_by_card(self):
        pass

######################### 复合组件 ########################
class BranchStore(Store):
    def __init__(self, name):
        self.name = name
        # 这句代码是实现组合模式的重点
        self.my_store_list = []

    def pay_by_card(self):
        print("店面[%s]的积分已累加进该会员卡" % self.name)
        for s in self.my_store_list:
            s.pay_by_card()

    # 添加店面
    def add(self, store):
        self.my_store_list.append(store)

    # 删除店面
    def remove(self, store):
        self.my_store_list.remove(store)

######################### 叶子组件 #############################
class JoinStore(Store):
    '''加盟店'''

    def __init__(self, name):
        self.name = name

    def pay_by_card(self):
        print("店面[%s]的积分已累加进该会员卡" % self.name)

    def add(self, store):
        print("无添加子店权限")

    def remove(self, store):
        print("无删除子店权限")


if __name__ == "__main__":
    # store = BranchStore("朝阳总店")
    # branch = BranchStore("海滨分店")
    # join_branch = JoinStore("昌平加盟1店")
    # join_branch2 = JoinStore("昌平加盟2店")
    #
    # branch.add(join_branch)
    # branch.add(join_branch2)
    #
    # store.add(branch)
    #
    # store.pay_by_card()
    # print(store.my_store_list)
    branch = BranchStore("海滨分店")
    # pay_by_card这个函数对外表现一致,所有的都调用这个方法、
    branch.pay_by_card()

享元模式

享元模式就是把所有对象共有的部分提取出来单独做一个对象,所以享元模式可以有很多个对象,但是单例模式只有一个对象

class FlyweightFactory(object):
    def __init__(self, cls):
        self._cls = cls
        self._instances = dict()
    # 使用*args, **kargs这样的方式抽象实现的cls的参数数量和类型
    def get_instance(self, *args, **kargs):
        # 如果键在字典中,返回这个键所对应的值。如果键不在字典中,向字典 中插入这个键
        return self._instances.setdefault(
                                (args, tuple(kargs.items())),
                                self._cls(*args, **kargs))


class Spam(object):
    # 我这里实现的是3个参数,这个随意
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

class Egg(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z


SpamFactory = FlyweightFactory(Spam)
EggFactory = FlyweightFactory(Egg)

assert SpamFactory.get_instance(1, 2, 3) is SpamFactory.get_instance(1, 2, 3)
assert EggFactory.get_instance('a', 'b', 'c') is EggFactory.get_instance('a', 'b', 'c')
assert SpamFactory.get_instance(1, 2, 3) is not EggFactory.get_instance(1, 2, 3)

代理模式

说白了,就是一个中介。想在访问一个类时做一些控制。增加中间层。

from abc import abstractmethod,ABCMeta

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

class RealSubject(Subject):
    def __init__(self,filename):
        self.filename = filename
        print("读取%s文件内容" % filename)
        f = open(filename)
        self.content = f.read()
        f.close()

    def get_content(self):
        return self.content

    def set_content(self, content):
        f = open(self.filename, 'w')
        f.write(content)
        f.close()


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

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


b = ProxyA("abc.txt")
print(b.get_content())
posted @ 2018-08-28 11:53  龙云飞谷  阅读(100)  评论(0编辑  收藏  举报