01-25.Python设计模式及应用场景(第九天: 组合模式)

2021-01-13  本文已影响0人  YuKalix

OPP七大设计原则

阅读提示: 常用的模式(学习ing持续补充):

单例模式, 工厂模式, 工厂方法 建造者模式 适配器模式 桥接模式

其他的模式可不用看, 个人能力没到那一层,自然也用不到. 了解即可,提供思路

一、创建型模式

对象的创建会消耗系统的很多资源,减少资源消耗,高效创建对象

1. 单例模式

使用场景:

  1. 项目配置类

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象

使用方式

class Settings:
    def __init__(self):
        pass

    # __new__方法会先于__init__执行
    def __new__(cls, *args, **kwargs):
        # hasattr()函数用于判断对象是否包含对应的属性。
        # instance翻译为实例
        if not hasattr(Settings, "_instance"):
            Settings._instance = object.__new__(cls)
        return Settings._instance

s = Settings()
b = Settings()
print(id(s))
print(id(b))
2964241711056
2964241711056

2. 工厂模式

创建对象时不会对客户端暴露创建逻辑, 并且使通过一个共同的接口来指向新创建的对象
个人理解: 将公用的的抽象成一层(接口):如画圆,正方形,菱形等 他们公用的就是我们口语说的"你要画什么形状".
向外只需要开放一个接口即可

简单工厂模式

优点: 客户端不需要修改代码
缺点: 当需要增加新的运算类的时候,不仅需新加运算类, 还要修改工厂类,违反了开闭原则
适用性:
当一个类不知道它所必须创建的对象的类的时候.
当一个类希望由它的子类来指定它所创建的对象的时候
当类将创建对象的职责委托给多个帮助子类的某一个,并且你希望哪一个帮助子类是代理者这一信息局部化的时候

image.png
class Shape:

    # 要求子类必须使用这个方法
    # 如果没使用raise异常
    def draw(self):
        raise NotImplemented


class Triangle(Shape):

    def draw(self):
        print("draw triangle")


class Square(Shape):

    def draw(self):
        print("draw square")



class ShapeFactory():

    def create(self, shape):
        if shape == "Circle":
            return Circle()
        elif shape == "Square":
            return Square()
        else:
            return None


if __name__ == '__main__':
    myShapeFactory = ShapeFactory()
    obj = myShapeFactory.create("Circle")
    obj.draw()

工厂方法

工厂方法模式(Factory Method pattern)
给每一类图形单位加一个工厂,
和简单工厂有区别,简单工厂模式只有一个工厂,工厂方法模式对每一个产品都有相应的工厂

优点: 增加一个运算类(例如N次方类),只需要增加运算类和相对应的工厂,两个类,不需要修改工厂类。
缺点: 增加运算类,会修改客户端代码,工厂方法只是把简单工厂的内部逻辑判断移到了客户端进行。

image.png
"""
抽象学校和课程, 它两之间建立关系
不同学校对应不同课程
"""


class AbstractSchool:
    name = ""
    addr = ""
    # 校长
    principal = ""

    def enroll(self, name, course):
        raise NotImplementedError

    # 学校简章
    def info(self):
        pass


# 抽象一个课程
class AbstractCourse:
    def __init__(self, name, time_range, study_type, fee):
        self.name = name
        self.time_range = time_range
        self.study_type = study_type
        # 学费
        self.fee = fee

    def enrooll_test(self):
        """
        入学测试
        :return:
        """
        print("课程[{0}]测试中...".format(self.name))

    def print_course_outline(self):
        '''打印课程大纲'''
        pass


class BengJingSchool(AbstractSchool):
    name = "北京校区"

    def create_course(self, course_type):
        if course_type == "py_ops":
            course = PythonCourse("Python开发", 7, "面授", 11000)
        elif course_type == "linux":
            course = LinuxCourse("Linux运维", 5, "面授", 12800)
        else:
            course = None
        return course

    def enroll(self, name, course):
        print("开始为新学员[{0}]办入学手续... ".format(name))
        print("帮学员[{0}]注册课程[{1}]...".format(name, course))
        course.enroll_test()

    def info(self):
        print("------[%s]-----" % self.name)


class YinChanSchool(AbstractSchool):
    name = "银川校区"

    def create_course(self, course_type):
        if course_type == "py_ops":
            course = PythonCourse("Python开发", 8, "面授", 100)
        elif course_type == "linux":
            course = LinuxCourse("Linux运维", 6, "面授", 200)
        else:
            course = None
        return course

    def enroll(self, name, course):
        print("开始为新学员[{0}]办入学手续... ".format(name))
        print("帮学员[{0}]注册课程[{1}]...".format(name, course))
        course.enroll_test()

    def info(self):
        print("------[%s]-----" % self.name)


class PythonCourse(AbstractCourse):
    def print_course_outline(self):
        outline = '''
        python 介绍
        python 基础语法
        python 函数式编程
        python 面向对象
        python 网络编程
        python web开发基础
        '''
        print(outline)

    def enroll_test(self):
        print("-------python入学测试-------")
        print("-------500道题答完了-------")
        print("-------通过了-------")


class LinuxCourse(AbstractCourse):
    def print_course_outline(self):
        outline = '''
        Linux 基础
        Linux 基本服务使用
        Linux 高级服务篇
        Linux Shell编程
        '''
        print(outline)

    def enroll_test(self):
        print("不用测试,是个人就能学...")


if __name__ == '__main__':
    BJ_School = BengJingSchool()
    YC_School = YinChanSchool()

    BJ_School.info()
    course_1 = BJ_School.create_course("py_ops")
    course_1_1 = BJ_School.create_course("linux")
    BJ_School.enroll("张三", course_1)
    BJ_School.enroll("李四", course_1_1)

    YC_School.info()
    course_2 = BJ_School.create_course("py_ops")
    YC_School.enroll("张三", course_2)
    YC_School.enroll("李四", course_2)
class ShapeFactory:
    '''工厂类'''

    def getShape(self):
        return self.shape_name

class Circle(ShapeFactory):

    def __init__(self):
        self.shape_name = "Circle"
    def draw(self):
        print('draw circle')

class Rectangle(ShapeFactory):
    def __init__(self):
        self.shape_name = "Retangle"

    def draw(self):
        print('draw Rectangle')


class ShapeInterfaceFactory(object):
    '''接口基类'''
    def create(self):
        '''把要创建的工厂对象装配进来'''
        raise  NotImplementedError

class ShapeCircle(ShapeInterfaceFactory):
    def create(self):
        return Circle()


class ShapeRectangle(ShapeInterfaceFactory):
    def create(self):
        return Rectangle()

if __name__ == '__main__':
    shape_interface = ShapeCircle()
    obj = shape_interface.create()
    obj.getShape()
    obj.draw()

    shape_interface2 = ShapeRectangle()
    obj2 = shape_interface2.create()
    obj2.draw()

抽象方法(暂时用不到, 了解即可, 是进一步抽象一层去扩展)

每一个模式都是针对一定问题的解决方案.抽象工程模式与工厂方法模式的最大区别就在于, 工厂方法模式针对的是一个产品等级结构;而抽象工程模式则需要面对多个产品等级结构.
产品族: AMD的主板丶芯片组丶CPU组成一个家族; Inter的主板丶芯片组丶CPU组成一个家族
产品等级:三个产品等级:主板丶芯片组丶CPU

image.png
class AbstractFactory(object):
    computer_name = ''

    def createCpu(self):
        pass

    def createMainboard(self):
        pass


class IntelFactory(AbstractFactory):
    computer_name = 'Intel I7-series computer '

    def createCpu(self):
        return IntelCpu('I7-6500')

    def createMainboard(self):
        return IntelMainBoard('Intel-6000')


class AmdFactory(AbstractFactory):
    computer_name = 'Amd 4 computer '

    def createCpu(self):
        return AmdCpu('amd444')

    def createMainboard(self):
        return AmdMainBoard('AMD-4000')


class AbstractCpu(object):
    series_name = ''
    instructions = ''
    arch = ''


class IntelCpu(AbstractCpu):
    def __init__(self, series):
        self.series_name = series


class IntelCpu(AbstractCpu):
    def __init__(self, series):
        self.series_name = series


class AmdCpu(AbstractCpu):
    def __init__(self, series):
        self.series_name = series


class AbstractMainboard(object):
    series_name = ''


class IntelMainBoard(AbstractMainboard):
    def __init__(self, series):
        self.series_name = series


class AmdMainBoard(AbstractMainboard):
    def __init__(self, series):
        self.series_name = series


class ComputerEngineer(object):

    def makeComputer(self, computer_obj):
        self.prepareHardwares(computer_obj)

    def prepareHardwares(self, computer_obj):
        self.cpu = computer_obj.createCpu()
        self.mainboard = computer_obj.createMainboard()

        info = '''------- computer [%s] info:
    cpu: %s
    mainboard: %s

 -------- End --------
        ''' % (computer_obj.computer_name, self.cpu.series_name, self.mainboard.series_name)
        print(info)


if __name__ == "__main__":
    engineer = ComputerEngineer()

    computer_factory = IntelFactory()
    engineer.makeComputer(computer_factory)

    computer_factory2 = AmdFactory()
    engineer.makeComputer(computer_factory2)

建造者模式

意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
创建一个Person基类, 白人,黑人,黄人继承Person, 每创建一个具体的人的时候不是直接继承白人黑人类, 而是引入第三方类(上帝),去操控建人类的步骤

# 建造者基类
class PersonBuilder():
    def BuildHead(self):
        pass

    def BuildBody(self):
        pass

    def BuildArm(self):
        pass

    def BuildLeg(self):
        pass


# 胖子
class PersonFatBuilder(PersonBuilder):
    type = '胖子'

    def BuildHead(self):
        print("构建%s的头" % self.type)

    def BuildBody(self):
        print("构建%s的身体" % self.type)

    def BuildArm(self):
        print("构建%s的手" % self.type)

    def BuildLeg(self):
        print("构建%s的脚" % self.type)


# 瘦子
class PersonThinBuilder(PersonBuilder):
    type = '瘦子'

    def BuildHead(self):
        print("构建%s的头" % self.type)

    def BuildBody(self):
        print("构建%s的身体" % self.type)

    def BuildArm(self):
        print("构建%s的手" % self.type)

    def BuildLeg(self):
        print("构建%s的脚" % self.type)


# 指挥者
class PersonDirector():
    pb = None

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

    def CreatePereson(self):
        self.pb.BuildHead()
        self.pb.BuildBody()
        self.pb.BuildArm()
        self.pb.BuildLeg()


def clientUI():
    pb = PersonThinBuilder()
    pd = PersonDirector(pb)
    pd.CreatePereson()

    pb = PersonFatBuilder()
    pd = PersonDirector(pb)
    pd.CreatePereson()
    return


if __name__ == '__main__':
    clientUI()

适配器模式

意图:将一个类的接口转换成客户希望的另一个接口.
Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
装接头

# 球员类
class Player():
    name = ''

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

    def Attack(self, name):
        pass

    def Defense(self):
        pass


# 前锋
class Forwards(Player):
    def __init__(self, name):
        Player.__init__(self, name)

    def Attack(self):
        print("前锋%s 进攻" % self.name)

    def Defense(self, name):
        print("前锋%s 防守" % self.name)


# 中锋(目标类)
class Center(Player):
    def __init__(self, name):
        Player.__init__(self, name)

    def Attack(self):
        print("中锋%s 进攻" % self.name)

    def Defense(self):
        print("中锋%s 防守" % self.name)


# 后卫
class Guards(Player):
    def __init__(self, name):
        Player.__init__(self, name)

    def Attack(self):
        print("后卫%s 进攻" % self.name)

    def Defense(self):
        print("后卫%s 防守" % self.name)


# 外籍中锋(待适配类)
# 中锋
class ForeignCenter(Player):
    name = ''

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

    def ForeignAttack(self):
        print("外籍中锋%s 进攻" % self.name)

    def ForeignDefense(self):
        print("外籍中锋%s 防守" % self.name)


# 翻译(适配类)
class Translator(Player):
    foreignCenter = None

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

    def Attack(self):
        self.foreignCenter.ForeignAttack()

    def Defense(self):
        self.foreignCenter.ForeignDefense()


def clientUI():
    b = Forwards('巴蒂尔')
    m = Guards('姚明')
    ym = Translator('麦克格雷迪')

    b.Attack()
    m.Defense()
    ym.Attack()
    ym.Defense()
    return


if __name__ == '__main__':
    clientUI()

桥接模式

拿汽车在路上行驶的来说.即有小汽车又有公共汽车, 它们都不但能在市区中的公路上行驶,也可以在告诉公路上行驶.
汽车有不同的类型, 路也有不同的形式 如何适应两个方面的变化
将抽象的部分与实现部分分离, 使它们都可以独立的变化

class AbstractRoad(object):
    '''公路基类'''
    car = None


class AbstractCar(object):
    '''车辆基类'''

    def run(self):
        pass


class Street(AbstractRoad):
    '''市区街道'''

    def run(self):
        self.car.run()
        print("在市区街道上行驶")


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

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


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

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


class Bus(AbstractCar):
    '''公共汽车'''

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


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

    #
    road2 = SpeedWay()
    road2.car = Bus()
    road2.run()
class AbstractRoad(object):
    '''公路基类'''
    car = None


class AbstractCar(object):
    '''车辆基类'''

    def run(self):
        pass


class People(object):
    pass


class Street(AbstractRoad):
    '''市区街道'''

    def run(self):
        self.car.run()
        print("在市区街道上行驶")


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

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


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

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


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

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


# 加上人
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()

组合模式

表示对象的部分-整体层次结构
用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象

树状管理,

image.png image.png

···python

应用组合模式的会员卡消费

那么我们就根据我们会员卡的消费,来模拟一下组合模式的实现吧!let's go!

首先:

1.我们的部件有,总店,分店,加盟店!

2.我们的部件共有的行为是:刷会员卡

3.部件之间的层次关系,也就是店面的层次关系是,总店下有分店、分店下可以拥有加盟店。

有了我们这几个必要条件后,我的要求就是目前店面搞活动当我在总店刷卡后,就可以累积相当于在所有下级店面刷卡的积分总额,设计的代码如下

class Store(object):
'''店面基类'''

#添加店面
def add(self,store):
    pass
#删除店面
def remove(self,store):
    pass
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)

这样在累积所有子店面积分的时候,就不需要去关心子店面的个数了,也不用关系是否是叶子节点还是组合节点了,也就是说不管是总店刷卡,还是加盟店刷卡,都可以正确有效的计算出活动积分。

什么情况下使用组合模式

引用大话设计模式的片段:“当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。”

···

二、结构型模式

对象的组成以及对象之间的依赖关系.影响后续程序的维护性丶代码的健壮性丶耦合性等

三、行为型模式

在对象的结构和对象创建问题解决后, 剩下对象行为问题,协作效率提高.

上一篇下一篇

猜你喜欢

热点阅读