行为模式

一、责任链模式

1.1概念

	责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对	象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。
    白话:
    责任链模式是一条链,链上有多个节点,每个节点都有各自的责任。当有输入时,第一个责任节点看自己能否处理该输入,如果可以就处理。如果不能就交由下一个责任节点处理。依次类推,直到最后一个责任节点。
    举例:
        假设现在有个需求来了,首先是实习生拿到这个需求。
        如果实习生能够实现,直接实现。如果不行,他把这个需求交给初级工程师。
        如果初级工程师能够实现,直接实现。如果不行,交给中级工程师。
        如果中级工程师能够实现,直接实现。如果不行,交给高级工程师。
        如果高级工程师能够实现,直接实现。如果不行,交给 CTO。
        如果 CTO能够实现,直接实现。如果不行,直接跟产品说,需求不做 

1.2角色

抽象处理者
具体处理者
客户端
:请假部门批准:项目主管----》部门经理----》总经理 

1.3优点

降低耦合度:一个对象无需知道是其他哪一个对象处理其请求

1.4缺点

	实这个模式有个缺陷,那就是虽然可以实现请求额度传递,但是也不保证在这里链中一定存在能处理请求的处理这类,一旦不存在,那么这个请求将一直存在与链中,如果将链设置成环形,那么这个请求将会永远在环形链中传递不休;还有一点就是由于请求的传递,请求无法立即精确的找到处理者,处理效率会降低。

1.5使用场景

1、在很长的if else的情况中,可以是的代码更易于维护

1.6图解

1.6代码示例

1、请假示例

from abc import ABCMeta, abstractmethod
class Handler(metaclass=ABCMeta):
    @abstractmethod
    def handle_leave(self, day):
        pass


class GeneralManagerHandler(Handler):
    def handle_leave(self, day):
        if day < 10:
            print("总经理批准%d天假"%day)
        else:
            print("呵呵")


class DepartmentManagerHandler(Handler):
    def __init__(self):
        self.successor = GeneralManagerHandler()  #责任链的后面的一个人
    def handle_leave(self, day):
        if day < 7:
            print("部门经理批准%d天假"%day)
        else:
            print("部门经理无权准假")
            self.successor.handle_leave(day)


class ProjectDirectorHandler(Handler):
    def __init__(self):
        self.successor = DepartmentManagerHandler()
    def handle_leave(self, day):
        if day < 3:
            print("项目主管批准%d天假")
        else:
            print("项目主管无权准假")
            self.successor.handle_leave(day)


day = 4
h = ProjectDirectorHandler()
h.handle_leave(day)
#过程
#抽象一个类方法,让其他类继承
#下一级(项目主管)的一个对象属性是上一级类(部门主管)的实例化
#继承类执行这个方法的时候有权处理就进行处理,没有权利处理就借用上一级类的这个抽象方法

2、模仿js事件处理

#--高级例子--模仿js事件处理
# JavaScript中假如有三个嵌套的div,每个div绑定一个事件,就像冒泡一样,先找里面的,
# 如果里面有就是里面的事件,如果里面没有就找上一层的。以此类推
from abc import ABCMeta, abstractmethod
class Handler(metaclass=ABCMeta):
    @abstractmethod
    def add_event(self, func):
        pass

    @abstractmethod
    def handle(self):
        pass


class BodyHandler(Handler):
    def __init__(self):
        self.func = None

    def add_event(self, func):
        self.func = func

    def handle(self):
        if self.func:
            return self.func()
        else:
            print("已到最后一级,无法处理")


class ElementHandler(Handler):
    def __init__(self, successor):
        self.func = None
        self.successor = successor

    def add_event(self, func):
        self.func = func

    def handle(self):
        if self.func:
            return self.func()
        else:
            return self.successor.handle()


# 客户端
# <body><div><a>

body = {'type': 'body', 'name': 'body', 'children': [], 'father': None}

div = {'type': 'div', 'name': 'div', 'children': [], 'father': body}

a = {'type': 'a', 'name': 'a', 'children': [], 'father': div}

body['children'].append(div)
div['children'].append(a)

body['event_handler'] = BodyHandler()
div['event_handler'] = ElementHandler(div['father']['event_handler'])
a['event_handler'] = ElementHandler(a['father']['event_handler'])


def attach_event(element, func):
    element['event_handler'].add_event(func)

#test

def func_div():
    print("这是给div的函数")

def func_a():
    print("这是给a的函数")

def func_body():
    print("这是给body的函数")

# attach_event(div, func_div)
attach_event(a, func_a)
# attach_event(body, func_body)
a['event_handler'].handle()

二、迭代器模式

2.1介绍

1、概念

提供一种方法顺序访问一个聚合函数一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示

2、如何解决

把在元素之间游走的责任交给迭代器,而不是聚合对象。

3、优点

 1、它支持以不同的方式遍历一个聚合对象。 2、迭代器简化了聚合类。 3、在同一个聚合上可以有多个遍历。 4、在迭代器模式中,增加新的聚合类和迭代器类都很方便,无须修改原有代码。

4、缺点

由于迭代器模式将存储数据和遍历数据的职责分离,增加新的聚合类需要对应增加新的迭代器类,类的个数成对增加,这在一定程度上增加了系统的复杂性。

5、注意实现

	迭代器模式就是分离了集合对象的遍历行为,抽象出一个迭代器类来负责,这样既可以做到不暴露集合的内部结构,又可让外部代码透明地访问集合内部的数据。

2.2实现方法

代器内部实现:__iter__、__next__方法

2.3图解

2.4代码实现

class LinkList:
    """链表 头结点保存链表的长度"""
    class Node:
        def __init__(self, item=None):
            self.item = item
            self.next = None

    class LinkListIterator:
        def __init__(self, node):
            self.node = node
        def __next__(self):
            if self.node:
                cur_node = self.node
                self.node = cur_node.next
                return cur_node.item
            else:
                raise StopIteration
        def __iter__(self):
            return self

    def __init__(self, iterable=None):
        self.head = LinkList.Node(0)
        self.tail = self.head
        self.extend(iterable)

    def append(self, obj):
        s = LinkList.Node(obj)
        self.tail.next = s
        self.tail = s

    def extend(self, iterable):
        for obj in iterable:
            self.append(obj)
        self.head.item += len(iterable)

    def __iter__(self):
        return self.LinkListIterator(self.head.next)

    def __len__(self):
        return self.head.item

    def __str__(self):
        return "<<"+", ".join(map(str, self))+">>"



li = [i for i in range(100)]
print(li)
lk = LinkList(li)
# for i in lk:
#     print(i)

print(lk)
# print(len(lk))

三、观察者模式

3.1内容

	定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于他的对象都得到通知并被自动更新。
	观察者模式又称‘发布-订阅’模式

3.2观察者模式

抽象主题(Subject)
具体主题(ConcreteSubject)——发布者
抽象观察者(Observer)
具体观察者(ConcreteObserver)——订阅者

3.3优点

目标和观察者之间的抽象耦合最小
支持广播通信

3.4缺点

多个观察者之间互不知道对方存在,因此一个观察者对主题的修改可能造成错误的更新。

3.5使用场景

当一个抽象模型有两方面,其中一方面依赖于另一方面。将这两者封装在独立对象中以使它们可以独立地改变和复用。
当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变(你要改变一个对象某一静态属性的所有值,不知道有多少个对象)。
当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的(你通知公司人其他同事一条消息)

3.6图解

3.7代码示例

from abc import ABCMeta, abstractmethod


class Observer(metaclass=ABCMeta):
    @abstractmethod
    def update(self, notice):
        pass


class Notice:
    def __init__(self):
        self.observers = [] # 记录该主体的观察者(订阅者)

    def attach(self, obs):
        self.observers.append(obs)

    def detach(self, obs):
        obs.company_info = None
        self.observers.remove(obs)

    def notify(self):
        for obj in self.observers:
            obj.update(self)


class ManagerNotice(Notice):
    def __init__(self, company_info=None):
        super().__init__()
        self.__company_info = company_info

    @property
    def company_info(self):
        return self.__company_info

    @company_info.setter
    def company_info(self, info):
        self.__company_info = info
        self.notify()



class Manager(Observer):
    def __init__(self):
        self.company_info = None

    def update(self, noti):
        self.company_info = noti.company_info


notice = ManagerNotice()

alex = Manager()
wusir = Manager()

# print(alex.company_info)
# print(wusir.company_info)

notice.attach(alex)
notice.attach(wusir)
#
notice.company_info="公司运行良好"
#
print(alex.company_info)
print(wusir.company_info)
#
notice.detach(wusir)
#
notice.company_info="公司要破产了"

print(alex.company_info)
print(wusir.company_info)

四、策略模型

4.1内容

策略模式(Strategy Pattern) 也叫 政策模式(Policy Pattern)。指的是对象具备某个行为,但是在不同的场景中,该行为有不同的实现算法。比如一个人的交税比率与他的工资有关,不同的工资水平对应不同的税率
#分离算法,选择实现
#在有多种算法相似的情况下,使用 if...else 或 switch...case 所带来的复杂性和臃肿性。

4.2角色

抽象策略(Strategy)规定策略或算法的行为;
具体策略(ConcreteStrategy)具体的策略或算法实现;
上下文(Context):用来操作策略的上下文环境,屏蔽高层模块(客户端)对策略,算法的直接访问,封装可能存在的变化;

4.3优点

算法多样性,且具备自由切换功能;
有效避免多重条件判断,增强了封装性,简化了操作,降低出错概率;
扩展性良好,策略类遵顼 里氏替换原则,可以很方便地进行策略扩展

4.4缺点

策略类数量增多,且所有策略类都必须对外暴露,以便客户端能进行选择

4.5使用场景

针对同一类型问题,有多种处理方式,每一种都能独立解决问题;
算法需要自由切换的场景;
需要屏蔽算法规则的场景

4.6图解

4.7示例代码

from abc import ABCMeta, abstractmethod
import random

class Sort(metaclass=ABCMeta):
    @abstractmethod
    def sort(self, data):
        pass


class QuickSort(Sort):
    def quick_sort(self, data, left, right):
        if left < right:
            mid = self.partition(data, left, right)
            self.quick_sort(data, left, mid - 1)
            self.quick_sort(data, mid + 1, right)

    def partition(self, data, left, right):
        tmp = data[left]
        while left < right:
            while left < right and data[right] >= tmp:
                right -= 1
            data[left] = data[right]
            while left < right and data[left] <= tmp:
                left += 1
            data[right] = data[left]
        data[left] = tmp
        return left

    def sort(self, data):
        print("快速排序")
        return self.quick_sort(data, 0, len(data) - 1)


class MergeSort(Sort):
    def merge(self, data, low, mid, high):
        i = low
        j = mid + 1
        ltmp = []
        while i <= mid and j <= high:
            if data[i] <= data[j]:
                ltmp.append(data[i])
                i += 1
            else:
                ltmp.append(data[j])
                j += 1

        while i <= mid:
            ltmp.append(data[i])
            i += 1

        while j <= high:
            ltmp.append(data[j])
            j += 1

        data[low:high + 1] = ltmp


    def merge_sort(self, data, low, high):
        if low < high:
            mid = (low + high) // 2
            self.merge_sort(data, low, mid)
            self.merge_sort(data, mid + 1, high)
            self.merge(data, low, mid, high)

    def sort(self, data):
        print("归并排序")
        return self.merge_sort(data, 0, len(data) - 1)


class Context:
    def __init__(self, data, strategy=None):
        self.data = data
        self.strategy = strategy

    def set_strategy(self, strategy):
        self.strategy = strategy

    def do_strategy(self):
        if self.strategy:
            self.strategy.sort(self.data)
        else:
            raise TypeError


li = list(range(100000))
random.shuffle(li)

context = Context(li, MergeSort())
context.do_strategy()
#print(context.data)

random.shuffle(context.data)

context.set_strategy(QuickSort())
context.do_strategy()

五、模板方法模式

5.1内容

	定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

5.2角色

抽象类:定义抽象的原子操作(钩子操作);实现一个模板方法的骨架
具体类:实现原子操作

5.3对设计原则的体现

模板方法很好的体现了开闭原则和里氏替换原则。
1、从设计上,先分离变与不变,然后把不变的部分抽取出来,定义到父类里面,比如算法骨架,比如一些公共的、固定的实现等等。这些不变的部分被封闭起来,尽量不去修改它了,要扩展新的功能,那就使用子类来扩展,通过子类来实现可变化的步骤,对于这种新增功能的做法是开放的。
2、能够实现统一的算法骨架,通过切换不同的具体实现来切换不同的功能,一个根本原因就是里氏替换原则,遵循这个原则,保证所有的子类实现的是同一个算法模板,并能在使用模板的地方,根据需要,切换不同的具体实现。

5.4使用场景

1、需要固定定义算法骨架,实现一个算法的不变的部分,并把可变的行为留给子类来实现的情况。
2、各个子类中具有公共行为,应该抽取出来,集中在一个公共类中去实现,从而避免代码重复
3、需要控制子类扩展的情况。模板方法模式会在特定的点来调用子类的方法,这样只允许在这些点进行扩展

5.5图解

5.6示例代码

from abc import ABCMeta, abstractmethod


class IOHandler(metaclass=ABCMeta):
    @abstractmethod
    def open(self, name):
        pass
    @abstractmethod
    def deal(self, change):
        pass
    @abstractmethod
    def close(self):
        pass

    def process(self, name, change):
        '''模板,就相当于是一个空盒子,可以往里面添加自己需要的功能。让这个函数去执行'''
        self.open(name)
        self.deal(change)															
        self.close()


class FileHandler(IOHandler):
    def open(self, name):
        print('打开文件')

    def deal(self, change):
        print('操作文件')

    def close(self):
        print('关闭文件')

obj = FileHandler()
obj.process('abc.txt','')
posted @ 2019-08-24 16:32  与凯学习  阅读(381)  评论(0)    收藏  举报