常见设计模式 (python代码实现)

1.创建型模式

单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

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

复制代码
 1 class Singleton(object):2     def __init__(self):3         pass4 5     def __new__(cls, *args, **kwargs):6         if not hasattr(Singleton, "_instance"): # 反射7             Singleton._instance = object.__new__(cls)8         return Singleton._instance9 
10 obj1 = Singleton()
11 obj2 = Singleton()
12 print(obj1, obj2) #<__main__.Singleton object at 0x004415F0> <__main__.Singleton object at 0x004415F0>
复制代码

 

工厂模式

工厂模式是一个在软件开发中用来创建对象的设计模式。

工厂模式包涵一个超类。这个超类提供一个抽象化的接口来创建一个特定类型的对象,而不是决定哪个对象可以被创建。

为了实现此方法,需要创建一个工厂类创建并返回。 

当程序运行输入一个“类型”的时候,需要创建于此相应的对象。这就用到了工厂模式。在如此情形中,实现代码基于工厂模式,可以达到可扩展,可维护的代码。当增加一个新的类型,不在需要修改已存在的类,只增加能够产生新类型的子类。

简短的说,当以下情形可以使用工厂模式:

1.不知道用户想要创建什么样的对象

2.当你想要创建一个可扩展的关联在创建类与支持创建对象的类之间。

一个例子更能很好的理解以上的内容:

  1. 我们有一个基类Person ,包涵获取名字,性别的方法 。有两个子类male 和female,可以打招呼。还有一个工厂类。
  2.  工厂类有一个方法名getPerson有两个输入参数,名字和性别。
  3.  用户使用工厂类,通过调用getPerson方法。

在程序运行期间,用户传递性别给工厂,工厂创建一个与性别有关的对象。因此工厂类在运行期,决定了哪个对象应该被创建

复制代码
class Person:def __init__(self):self.name = Noneself.gender = Nonedef getName(self):return self.namedef getGender(self):return self.genderclass Male(Person):def __init__(self, name):print "Hello Mr." + nameclass Female(Person):def __init__(self, name):print "Hello Miss." + nameclass Factory:def getPerson(self, name, gender):if gender == ‘M':return Male(name)if gender == 'F':return Female(name)if __name__ == '__main__':factory = Factory()person = factory.getPerson("Chetan", "M")
复制代码

建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

相关模式:思路和模板方法模式很像,模板方法是封装算法流程,对某些细节,提供接口由子类修改,建造者模式更为高层一点,将所有细节都交由子类实现

一个例子更能很好的理解以上的内容:

1. 有一个接口类,定义创建对象的方法。一个指挥员类,接受创造者对象为参数。两个创造者类,创建对象方法相同,内部创建可自定义

2.一个指挥员,两个创造者(瘦子 胖子),指挥员可以指定由哪个创造者来创造

复制代码
from abc import ABCMeta, abstractmethodclass Builder():__metaclass__ = ABCMeta@abstractmethoddef draw_left_arm(self):pass@abstractmethoddef draw_right_arm(self):pass@abstractmethoddef draw_left_foot(self):pass@abstractmethoddef draw_right_foot(self):pass@abstractmethoddef draw_head(self):pass@abstractmethoddef draw_body(self):passclass Thin(Builder):def draw_left_arm(self):print '画左手'def draw_right_arm(self):print '画右手'def draw_left_foot(self):print '画左脚'def draw_right_foot(self):print '画右脚'def draw_head(self):print '画头'def draw_body(self):print '画瘦身体'class Fat(Builder):def draw_left_arm(self):print '画左手'def draw_right_arm(self):print '画右手'def draw_left_foot(self):print '画左脚'def draw_right_foot(self):print '画右脚'def draw_head(self):print '画头'def draw_body(self):print '画胖身体'class Director():def __init__(self, person):self.person=persondef draw(self):self.person.draw_left_arm()self.person.draw_right_arm()self.person.draw_left_foot()self.person.draw_right_foot()self.person.draw_head()self.person.draw_body()if __name__=='__main__':thin=Thin()fat=Fat()director_thin=Director(thin)director_thin.draw()director_fat=Director(fat)director_fat.draw()
复制代码

 

原型模式

 

原型模式

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
原型模式本质就是克隆对象,所以在对象初始化操作比较复杂的情况下,很实用,能大大降低耗时,提高性能,因为“不用重新初始化对象,而是动态地获得对象运行时的状态”。

浅拷贝(Shallow Copy):指对象的字段被拷贝,而字段引用的对象不会被拷贝,拷贝的对象和源对象只是名称相同,但是他们共用一个实体。
深拷贝(deep copy):对对象实例中字段引用的对象也进行拷贝。

复制代码
import copy
from collections import OrderedDictclass Book:def __init__(self, name, authors, price, **rest):'''rest的例子有:出版商、长度、标签、出版日期'''self.name = nameself.authors = authorsself.price = price  # 单位为美元self.__dict__.update(rest)def __str__(self):mylist = []ordered = OrderedDict(sorted(self.__dict__.items()))for i in ordered.keys():mylist.append('{}: {}'.format(i, ordered[i]))if i == 'price':mylist.append('$')mylist.append('\n')return ''.join(mylist)class Prototype:def __init__(self):self.objects = dict()def register(self, identifier, obj):self.objects[identifier] = objdef unregister(self, identifier):del self.objects[identifier]def clone(self, identifier, **attr):found = self.objects.get(identifier)if not found:raise ValueError('Incorrect object identifier: {}'.format(identifier))obj = copy.deepcopy(found)obj.__dict__.update(attr)return objdef main():b1 = Book('The C Programming Language', ('Brian W. Kernighan', 'Dennis M.Ritchie'),price=118, publisher='Prentice Hall', length=228, publication_date='1978-02-22',tags=('C', 'programming', 'algorithms', 'data structures'))prototype = Prototype()cid = 'k&r-first'prototype.register(cid, b1)b2 = prototype.clone(cid, name='The C Programming Language(ANSI)', price=48.99,length=274, publication_date='1988-04-01', edition=2)for i in (b1, b2):print(i)print("ID b1 : {} != ID b2 : {}".format(id(b1), id(b2)))if __name__ == '__main__':main()"""
>>> python3 prototype.py
authors: ('Brian W. Kernighan', 'Dennis M. Ritchie')
length: 228
name: The C Programming Language
price: 118$
publication_date: 1978-02-22
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')authors: ('Brian W. Kernighan', 'Dennis M. Ritchie')
edition: 2
length: 274
name: The C Programming Language (ANSI)
price: 48.99$
publication_date: 1988-04-01
publisher: Prentice Hall
tags: ('C', 'programming', 'algorithms', 'data structures')ID b1 : 140004970829304 != ID b2 : 140004970829472
"""
复制代码

 

2.结构型模式

适配器模式

所谓适配器模式是指是一种接口适配技术,它可通过某个类来使用另一个接口与之不兼容的类,运用此模式,两个类的接口都无需改动。

适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况,比如在需要对早期代码复用一些功能等应用上很有实际价值。

解释二:

适配器模式(Adapter Pattern):将一个类的接口转换成为客户希望的另外一个接口.Adapter Pattern使得原本由于接口不兼容而不能一起工作的那些类可以一起工作.
应用场景:系统数据和行为都正确,但接口不符合时,目的是使控制范围之外的一个原有对象与某个接口匹配,适配器模式主要应用于希望复用一些现存的类,但接口又与复用环境不一致的情况

适配器模式

复制代码
class Target(object):def request(self):print "普通请求"class Adaptee(object):def specific_request(self):print "特殊请求"class Adapter(Target):def __init__(self):self.adaptee = Adaptee()def request(self):self.adaptee.specific_request()if __name__ == "__main__":target = Adapter()target.request()
复制代码

 

修饰器模式

该模式虽名为修饰器,但这并不意味着它应该只用于让产品看起来更漂亮。修饰器模式通常用于扩展一个对象的功能。这类扩展的实际例子有,给枪加一个消音器、使用不同的照相机镜头

复制代码
import functools
def memoize(fn):known = dict()@functools.wraps(fn)def memoizer(*args):if args not in known:known[args] = fn(*args)return known[args]return memoizer
@memoize
def nsum(n):'''返回前n个数字的和'''assert(n >= 0), 'n must be >= 0'return 0 if n == 0 else n + nsum(n-1)
@memoize
def fibonacci(n):'''返回斐波那契数列的第n个数'''assert(n >= 0), 'n must be >= 0'return n if n in (0, 1) else fibonacci(n-1) + fibonacci(n-2)
if __name__ == '__main__':from timeit import Timermeasure = [ {'exec':'fibonacci(100)', 'import':'fibonacci','func':fibonacci},{'exec':'nsum(200)', 'import':'nsum','func':nsum} ]for m in measure:t = Timer('{}'.format(m['exec']), 'from __main__ import{}'.format(m['import']))print('name: {}, doc: {}, executing: {}, time:{}'.format(m['func'].__name__, m['func'].__doc__,m['exec'], t.timeit()))"""
>>> python3 mymath.py
name: fibonacci, doc: Returns the nth number of the Fibonacci
sequence, executing: fibonacci(100), time: 0.4169441329995607
name: nsum, doc: Returns the sum of the first n numbers,
executing: nsum(200), time: 0.4160157349997462
"""
复制代码

 

 

外观模式

外观模式又叫做门面模式。在面向对象程序设计中,解耦是一种推崇的理念。但事实上由于某些系统中过于复杂,从而增加了客户端与子系统之间的耦合度。例如:在家观看多媒体影院时,更希望按下一个按钮就能实现影碟机,电视,音响的协同工作,而不是说每个机器都要操作一遍。这种情况下可以采用外观模式,即引入一个类对子系统进行包装,让客户端与其进行交互。

外观模式(Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。

复制代码
from enum import Enum
from abc import ABCMeta, abstractmethodState = Enum('State', 'new running sleeping restart zombie')class User:passclass Process:passclass File:passclass Server(metaclass=ABCMeta):@abstractmethoddef __init__(self):passdef __str__(self):return self.name@abstractmethoddef boot(self):pass@abstractmethoddef kill(self, restart=True):passclass FileServer(Server):def __init__(self):'''初始化文件服务进程要求的操作'''self.name = 'FileServer'self.state = State.newdef boot(self):print('booting the {}'.format(self))'''启动文件服务进程要求的操作'''self.state = State.runningdef kill(self, restart=True):print('Killing {}'.format(self))'''终止文件服务进程要求的操作'''self.state = State.restart if restart else State.zombiedef create_file(self, user, name, permissions):'''检查访问权限的有效性、用户权限等'''print("trying to create the file '{}' for user '{}' with permissions{}".format(name, user, permissions))class ProcessServer(Server):def __init__(self):'''初始化进程服务进程要求的操作'''self.name = 'ProcessServer'self.state = State.newdef boot(self):print('booting the {}'.format(self))'''启动进程服务进程要求的操作'''self.state = State.runningdef kill(self, restart=True):print('Killing {}'.format(self))'''终止进程服务进程要求的操作'''self.state = State.restart if restart else State.zombiedef create_process(self, user, name):'''检查用户权限和生成PID等'''print("trying to create the process '{}' for user '{}'".format(name, user))class WindowServer:passclass NetworkServer:passclass OperatingSystem:'''外观'''def __init__(self):self.fs = FileServer()self.ps = ProcessServer()def start(self):[i.boot() for i in (self.fs, self.ps)]def create_file(self, user, name, permissions):return self.fs.create_file(user, name, permissions)def create_process(self, user, name):return self.ps.create_process(user, name)def main():os = OperatingSystem()os.start()os.create_file('foo', 'hello', '-rw-r-r')os.create_process('bar', 'ls /tmp')if __name__ == '__main__':main()"""
booting the FileServer
booting the ProcessServer
trying to create the file 'hello' for user 'foo' with permissions-rw-r-r
trying to create the process 'ls /tmp' for user 'bar'
"""
复制代码

 

享元模式

运用共享技术有效地支持大量细粒度的对象。
内部状态:享元对象中不会随环境改变而改变的共享部分。比如围棋棋子的颜色。
外部状态:随环境改变而改变、不可以共享的状态就是外部状态。比如围棋棋子的位置。

应用场景:程序中使用了大量的对象,如果删除对象的外部状态,可以用相对较少的共享对象取代很多组对象,就可以考虑使用享元模式。

复制代码
 1 import random2 from enum import Enum3 TreeType = Enum('TreeType', 'apple_tree cherry_tree peach_tree')4 5 class Tree:6     pool = dict()7     def __new__(cls, tree_type):8         obj = cls.pool.get(tree_type, None)9         if not obj:
10             obj = object.__new__(cls)
11             cls.pool[tree_type] = obj
12             obj.tree_type = tree_type
13         return obj
14 
15     def render(self, age, x, y):
16         print('render a tree of type {} and age {} at ({}, {})'.format(self.tree_type, age, x, y))
17 
18 
19 def main():
20     rnd = random.Random()
21     age_min, age_max = 1, 30 # 单位为年
22     min_point, max_point = 0, 100
23     tree_counter = 0
24     for _ in range(10):
25         t1 = Tree(TreeType.apple_tree)
26         t1.render(rnd.randint(age_min, age_max),
27                 rnd.randint(min_point, max_point),
28                 rnd.randint(min_point, max_point))
29         tree_counter += 1
30     for _ in range(3):
31         t2 = Tree(TreeType.cherry_tree)
32         t2.render(rnd.randint(age_min, age_max),
33                 rnd.randint(min_point, max_point),
34                 rnd.randint(min_point, max_point))
35         tree_counter += 1
36     for _ in range(5):
37         t3 = Tree(TreeType.peach_tree)
38         t3.render(rnd.randint(age_min, age_max),
39                     rnd.randint(min_point, max_point),
40                     rnd.randint(min_point, max_point))
41         tree_counter += 1
42 
43     print('trees rendered: {}'.format(tree_counter))
44     print('trees actually created: {}'.format(len(Tree.pool)))
45     t4 = Tree(TreeType.cherry_tree)
46     t5 = Tree(TreeType.cherry_tree)
47     t6 = Tree(TreeType.apple_tree)
48     print('{} == {}? {}'.format(id(t4), id(t5), id(t4) == id(t5)))
49     print('{} == {}? {}'.format(id(t5), id(t6), id(t5) == id(t6)))
50 
51 main()
52 
53 """
54 render a tree of type TreeType.apple_tree and age 28 at (29, 80)
55 render a tree of type TreeType.apple_tree and age 28 at (38, 94)
56 render a tree of type TreeType.apple_tree and age 16 at (82, 84)
57 render a tree of type TreeType.apple_tree and age 18 at (43, 98)
58 render a tree of type TreeType.apple_tree and age 2 at (84, 72)
59 render a tree of type TreeType.apple_tree and age 16 at (89, 29)
60 render a tree of type TreeType.apple_tree and age 30 at (91, 53)
61 render a tree of type TreeType.apple_tree and age 12 at (92, 73)
62 render a tree of type TreeType.apple_tree and age 3 at (11, 54)
63 render a tree of type TreeType.apple_tree and age 1 at (34, 59)
64 render a tree of type TreeType.cherry_tree and age 11 at (67, 72)
65 render a tree of type TreeType.cherry_tree and age 27 at (65, 81)
66 render a tree of type TreeType.cherry_tree and age 27 at (10, 48)
67 render a tree of type TreeType.peach_tree and age 11 at (35, 38)
68 render a tree of type TreeType.peach_tree and age 3 at (58, 83)
69 render a tree of type TreeType.peach_tree and age 18 at (73, 50)
70 render a tree of type TreeType.peach_tree and age 24 at (94, 3)
71 render a tree of type TreeType.peach_tree and age 4 at (2, 9)
72 trees rendered: 18
73 trees actually created: 3
74 4866032 == 4866032? True
75 4866032 == 4742704? False
76 
77 """
复制代码

 

模型-视图-控制器模式

代理模式

3.行为型模式

责任链模式

命令模式

解释器模式

观察者模式

状态模式

 

策略模式

模板模式

 

转载于:https://www.cnblogs.com/ExMan/p/10427172.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/278276.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记录一次解决httpcline请求https报handshake_failure错误

概述 当使用httpclinet发起https请求时报如下错误&#xff1a; javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failureat com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)at com.sun.net.ssl.internal.ssl.Alerts.getSSLExcep…

桌面程序explorer_备份Internet Explorer 7搜索提供程序列表

桌面程序explorerIf you are both an IE user and a fan of using custom search providers in your search box, you might be interested to know how you can back up that list and/or restore it on another computer. Yes, this article is boring, but we’re trying to…

GreenPlum数据库故障恢复测试

本文介绍gpdb的master故障及恢复测试以及segment故障恢复测试。 环境介绍&#xff1a;Gpdb版本&#xff1a;5.5.0 二进制版本操作系统版本&#xff1a; centos linux 7.0Master segment: 192.168.1.225/24 hostname: mfsmasterStadnby segemnt: 192.168.1.227/24 hostname: ser…

书评:Just the Computer Essentials(Vista)

Normally we try and focus on articles about how to customize your computer, but today we’ll take a break from that and do a book review. This is something I’ve not done before, so any suggestions or questions will be welcomed in the comments. 通常&#x…

python学习

为了学会能学&#xff0c;不负时间&#xff0c;为了那简练的美&#xff01; 为了一片新天地。 /t 对齐 python : # 99乘法表i 0while i < 9 : i 1 j 0 while j < i : j 1 print(j ,* , i,"" , i*j , end\t) #空格不能对齐 制表符…

hey 安装_如何在助理扬声器上调整“ Hey Google”的灵敏度

hey 安装Vantage_DS/ShutterstockVantage_DS / ShutterstockThe Google Assistant is a useful tool that allows you to control your smart home, check the weather, and more. Unfortunately, the Assistant might not hear you in a noisy environment or it might activa…

EXCEL如何进行多条件的数据查找返回

在使用EXCEL时经常会碰到一个表里的同一款产品每天的销量都不一样&#xff0c;然后我们需要查导出每一款产品每天的销量&#xff0c;即一对多条件查找。这个教复杂&#xff0c;我们要用到好几个函数的综合&#xff0c;下面小编来教你吧。 工具/原料 EXCEL软件&#xff08;本文使…

如何将Google幻灯片转换为PowerPoint

If someone sent you a presentation on Google Slides, but you’d rather work on it in Microsoft PowerPoint, you can easily convert it to a .pptx file in just a few simple steps. Here’s how it’s done. 如果有人在Google幻灯片上向您发送了演示文稿&#xff0c;但…

XP调整禁用页面文件

NOTE: You shouldn’t disable your page file unless you really really know what you are doing. 注意&#xff1a;除非您真的很清楚自己在做什么&#xff0c;否则不应该禁用页面文件。 If your computer has 1 GB of RAM or more, disabling the page file can speed up XP…

如何在Windows 10的命令提示符中更改目录

One of the first things you’ll need to learn as you become more familiar with Command Prompt on Windows 10 is how to change directories in the operating system’s file system. There are a few ways you can do this, so we’ll walk you through them. 随着您对…

MySQL优化总结

2019独角兽企业重金招聘Python工程师标准>>> 从这几天看MySQL性能优化来看&#xff0c;基本的思路就是分分分&#xff0e;&#xff0e;&#xff0e; 1&#xff0c;分读&#xff0c;用缓存来分摊读表的压力; 2&#xff0c;读写分离&#xff0c;主从分离&#xff0c;写…

将背景色添加到Word 2007文档中

Instead of using the standard white background with Word documents, here is how to add some background color to spice up your documents. 代替在Word文档中使用标准的白色背景&#xff0c;这是如何添加一些背景颜色来为文档增添色彩。 Open your word document and ch…

jquery实现增删改(伪)-老男孩作业day13

使用jquery进行&#xff0c;文件的编写&#xff0c;实现自增id,删除&#xff0c;添加&#xff0c;编辑模式。 jquery放在本地&#xff0c;src"jquery_js.js" 可以改成其他&#xff0c;或者在线的路径 readme<!DOCTYPE html> <html lang"en"> &…

uoj#119. 【UR #8】决战圆锥曲线(线段树+复杂度分析)

题解 传送门 题解 然而要我来说我感觉只是个爆搜啊…… //minamoto #include<bits/stdc.h> #define R register #define ll long long #define ls (p<<1) #define rs (p<<1|1) #define fp(i,a,b) for(R int ia,Ib1;i<I;i) #define fd(i,a,b) for(R int ia…

如何在Raspberry Pi上设置两因素身份验证

Kiklas/ShutterstockKiklas /快门The Raspberry Pi is everywhere now, which is why it’s caught the eye of threat actors and cybercriminals. We’ll show you how to secure your Pi with two-factor authentication. Raspberry Pi现在无处不在&#xff0c;这就是为什么…

vue 开发环境搭建

1.创建vue项目 1.node js 生成项目&#xff0c;编译项目 2.hbuilder 开发环境 1.下载安装node js http://nodejs.cn/download/ 确认是否安装成功 如果安装不了 代码错误2503 解决方法&#xff1a; 管理员命令运行cmd; cd\ cd C:\Users\Administrator\Desktop msiexec/package n…

iphone视图放大_如何将iPhone用作放大镜

iphone视图放大It’s a common problem: Some things are just too hard to see. Usually, they’re too far away, too dark, or too small. With a feature called Magnifier, your iPhone can function as a magnifying glass and sight aid. Here’s how to use it. 这是一…

discord linux_如何在Discord中应用文本格式

discord linuxDiscord allows for text-and audio-based chatting between gamers and other like-minded individuals. If you want to make a bigger impact on Discord, you can use formatting to jazz up your text-based messages. Here’s how. Discord允许游戏玩家和其…

一张图看懂阿里云网络产品[十二]云企业网

2019独角兽企业重金招聘Python工程师标准>>> 摘要&#xff1a; 阿里云致力于为用户提供优质、高效、稳定的网络传输环境&#xff0c;云企业网&#xff08;Cloud Enterprise Network&#xff09;将提供一种能够快速构建混合云和分布式业务系统的全球网络&#xff0c;…

# 2019-2020.3 《java程序设计》第一周学习总结

2019-2020-3 《Java 程序设计》第一周学习总结 在本周的学习中&#xff0c;学习到了好多也收获了好多&#xff0c;从最基础的安装虚拟机开始&#xff0c;根据老师的博客中的教程一步一步的进行&#xff0c;在这过程中也遇到了好多问题&#xff0c;因为是初步接触Linux系统&…