常見設計模式 (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.pswp.cn/news/278276.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/278276.shtml
英文地址,請注明出處:http://en.pswp.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…

C++內聯函數(inline function)

c從c中繼承的一個重要特征就是效率。假如c的效率明顯低于c的效率&#xff0c;那么就會有很大的一批程序員不去使用c了。 在c中我們經常把一些短并且執行頻繁的計算寫成宏&#xff0c;而不是函數&#xff0c;這樣做的理由是為了執行效率&#xff0c;宏可以避免函數調用的開銷&am…

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…

RxSwift筆記七其他操作符

簡介 git地址: https://github.com/ReactiveX/RxSwift參考資料:http://t.swift.gg/d/2-rxswiftReactiveX是通過可觀察的流實現異步編程的一種API&#xff0c;它結合了觀察者模式、迭代器模式和函數式編程的精華&#xff0c;RxSwift 是 ReactiveX 編程思想的一種實現。 復制代碼…

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;但…

Linux 常用命令:文本查看篇

前言 Linux常用命令中&#xff0c;除了cat還有很多其他用于文本查看的命令。本文將簡單介紹一下這些文本查看的命令。 全文本顯示--cat cat可能是常用的一個文本查看命令了&#xff0c;使用方法也很簡單&#xff1a; cat file #全文本顯示在終端cat -n file #顯示全文本&#…

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…

復制數據庫

1.首先手動創建新的數據庫 CREATE DATABASE new-DB DEFAULT CHARACTER SET utf8mb4; 2.使用mysqldump命令。結果&#xff0c;會連同數據一起復制過去。 mysqldump old-DB -u root -pXX --add-drop-table | mysql new-DB -u root -pXX轉載于:https://www.cnblogs.com/clcliangc…

labelme2coco問題:TypeError: Object of type 'int64' is not JSON serializable

最近在做MaskRCNN 在自己的數據&#xff08;labelme&#xff09;轉為COCOjson格式遇到問題&#xff1a;TypeError: Object of type int64 is not JSON serializable 原因是numpy的數據類型不能被json兼容 最簡單的做法是自己寫一個序列類 class MyEncoder(json.JSONEncoder):de…

如何在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. 隨著您對…

jQuery 購物車

html代碼 <!--shoppingCar start--> <table id"TB"> <tr> <td colspan"7" class"title"> <div class"img_box"> <div class"logo_box"> <img src"img/jd…

MySQL優化總結

2019獨角獸企業重金招聘Python工程師標準>>> 從這幾天看MySQL性能優化來看&#xff0c;基本的思路就是分分分&#xff0e;&#xff0e;&#xff0e; 1&#xff0c;分讀&#xff0c;用緩存來分攤讀表的壓力; 2&#xff0c;讀寫分離&#xff0c;主從分離&#xff0c;寫…

瘋狂java講義

封裝&#xff1a; 封裝&#xff1a;將對象狀態信息隱藏在對象內部&#xff0c;不允許外部程序直接訪問對象內部信息&#xff0c;而是用類所提供的方法訪問和操作。訪問控制符&#xff1a;private&#xff08;當前類訪問權&#xff09; ,protected&#xff08;子類訪問&#xff…

將背景色添加到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"> &…