Python設(shè)計(jì)模式之策略模式

策略模式

大多數(shù)問題都可以使用多種方法來解決。以排序問題為例,對(duì)于以一定次序把元素放入一個(gè)列表,排序算法有很多。通常來說,沒有公認(rèn)最適合所有場(chǎng)景的算法(請(qǐng)參考網(wǎng)頁[t.cn/RqrBZJQ])。一些不同的評(píng)判標(biāo)準(zhǔn)能幫助我們?yōu)椴煌膱?chǎng)景選擇不同的排序算法,其中應(yīng)該考慮的有以下幾個(gè)。

  • 需要排序的元素?cái)?shù)量:這被稱為輸入大小。當(dāng)輸入較少時(shí),幾乎所有排序算法的表現(xiàn)都很好,但對(duì)于大量輸入,只有部分算法具有不錯(cuò)的性能。
  • 算法的最佳/平均/最差時(shí)間復(fù)雜度:時(shí)間復(fù)雜度是算法運(yùn)行完成所花費(fèi)的(大致)時(shí)間長短,不考慮系數(shù)和低階項(xiàng)(在算法分析中,只考慮時(shí)間復(fù)雜度函數(shù)的最高次項(xiàng),不考慮低階項(xiàng),也忽略最高次項(xiàng)的系數(shù))。這是選擇算法的最常見標(biāo)準(zhǔn),但這個(gè)標(biāo)準(zhǔn)并不總是那么充分。
  • 算法的空間復(fù)雜度:空間復(fù)雜度是充分地運(yùn)行一個(gè)算法所需要的(大致)物理內(nèi)存量。在我們處理大數(shù)據(jù)或在嵌入式系統(tǒng)(通常內(nèi)存有限)中工作時(shí),這個(gè)因素非常重要。
  • 算法的穩(wěn)定性:在執(zhí)行一個(gè)排序算法之后,如果能保持相等值元素原來的先后相對(duì)次序,則認(rèn)為它是穩(wěn)定的。
  • 算法的代碼實(shí)現(xiàn)復(fù)雜度:如果兩個(gè)算法具有相同的時(shí)間/空間復(fù)雜度,并且都是穩(wěn)定的,那么知道哪個(gè)算法更易于編碼實(shí)現(xiàn)和維護(hù)也是很重要的。

可能還有更多的評(píng)判標(biāo)準(zhǔn)值得考慮,但重要的是,我們真的只能使用單個(gè)排序算法來應(yīng)對(duì)所有情況嗎?答案當(dāng)然不是。一個(gè)更好的方案是把所有排序算法納為己用,然后使用上面提到的標(biāo)準(zhǔn)針對(duì)當(dāng)前情況選擇最好的算法。這就是策略模式的作用。

策略模式(Strategy pattern)鼓勵(lì)使用多種算法來解決一個(gè)問題,其殺手級(jí)特性是能夠在運(yùn)行時(shí)透明地切換算法(客戶端代碼對(duì)變化尤感知)。因此,如果你有兩種算法,并且知道其中一種對(duì)少量輸入效果更好,另一種對(duì)大量輸入效果更好,則可以使用策略模式在運(yùn)行時(shí)基于輸入數(shù)據(jù)決定使用哪種算法。

以下示例來自于Github:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
http://stackoverflow.com/questions/963965/how-is-this-strategy-pattern
 -written-in-python-the-sample-in-wikipedia
In most of other languages Strategy pattern is implemented via creating some
base strategy interface/abstract class and subclassing it with a number of
concrete strategies (as we can see at
http://en.wikipedia.org/wiki/Strategy_pattern), however Python supports
higher-order functions and allows us to have only one class and inject
functions into it's instances, as shown in this example.
"""
import types


class StrategyExample:

    def __init__(self, func=None):
        self.name = 'Strategy Example 0'
        if func is not None:
            self.execute = types.MethodType(func, self)

    def execute(self):
        print(self.name)


def execute_replacement1(self):
    print(self.name + ' from execute 1')


def execute_replacement2(self):
    print(self.name + ' from execute 2')


if __name__ == '__main__':
    strat0 = StrategyExample()

    strat1 = StrategyExample(execute_replacement1)
    strat1.name = 'Strategy Example 1'

    strat2 = StrategyExample(execute_replacement2)
    strat2.name = 'Strategy Example 2'

    strat0.execute()
    strat1.execute()
    strat2.execute()

### OUTPUT ###
# Strategy Example 0
# Strategy Example 1 from execute 1
# Strategy Example 2 from execute 2

現(xiàn)實(shí)生活的例子

去機(jī)場(chǎng)趕飛機(jī)是現(xiàn)實(shí)中使用策略模式的一個(gè)恰當(dāng)例子。

  • 如果想省錢,并且早點(diǎn)出發(fā),那么可以坐公交車/地鐵。
  • 如果不介意支付停車費(fèi),并且有自己的汽車,那么可以開車去。
  • 如果沒有自己的車,又比較急,則可以打車。

這是費(fèi)用、時(shí)間、便利性等因素之間的一個(gè)折中權(quán)衡。下圖展示了以多種方式(策略)去機(jī)場(chǎng)的一個(gè)例子,經(jīng)www.sourcemaking.com允許使用(請(qǐng)參考網(wǎng)頁[t.cn/RqrBAeJ])。

軟件的例子

Python的sorted()和list.sort()函數(shù)是策略模式的例子。兩個(gè)函數(shù)都接受一個(gè)命名參數(shù)key,這個(gè)參數(shù)本質(zhì)上是實(shí)現(xiàn)了一個(gè)排序策略的函數(shù)的名稱(請(qǐng)參考[Eckel08,第202頁])。

下面的例子(代碼在文件langs.py中)展示了如何用以下方式使用兩種不同的策略對(duì)編程語言進(jìn)行排序。

  • 按字母順序
  • 基于它們的流行度(使用TIOBE指數(shù),請(qǐng)參考網(wǎng)頁[t.cn/RGQ0jM7])

namedtuple編程語言(請(qǐng)參考網(wǎng)頁[t.cn/RqrBUrf])用于保存編程語言的統(tǒng)計(jì)數(shù)據(jù)。命名元組是一種易于創(chuàng)建、輕量、不可變的對(duì)象類型,與普通元組兼容,但也可以看作一個(gè)對(duì)象(可以使用常見的類表示法通過名稱調(diào)用)。命名元組可用于替代以下各項(xiàng)(請(qǐng)參考網(wǎng)頁[t.cn/RqrBGwP])。

  • 在我們關(guān)注不可變特性時(shí),替代一個(gè)類。
  • 在值得使用對(duì)象表示法來創(chuàng)建可讀性更高的代碼時(shí),替代一個(gè)元組。

順便說明一下pprint和attrgetter模塊。pprint模塊用于美化輸出一個(gè)數(shù)據(jù)結(jié)構(gòu),attrgetter用于通過屬性名訪問class或namedtuple的屬性。也可以使用一個(gè)lambda函數(shù)來替代使用attrgetter,但我覺得attrgetter的可讀性更高。

import pprint  
from collections import namedtuple
from operator import attrgetter

if __name__ == '__main__':
    ProgrammingLang = namedtuple('ProgrammingLang', 'name ranking')
    stats = (('Ruby', 14), ('Javascript', 8), ('Python', 7),
                  ('Scala', 31), ('Swift', 18), ('Lisp', 23))
    lang_stats = [ProgrammingLang(n, r) for n, r in stats]
    pp = pprint.PrettyPrinter(indent=5)
    pp.pprint(sorted(lang_stats, key=attrgetter('name')))
    print()
    pp.pprint(sorted(lang_stats, key=attrgetter('ranking')))
[    ProgrammingLang(name='Javascript', ranking=8),
     ProgrammingLang(name='Lisp', ranking=23),
     ProgrammingLang(name='Python', ranking=7),
     ProgrammingLang(name='Ruby', ranking=14),
     ProgrammingLang(name='Scala', ranking=31),
     ProgrammingLang(name='Swift', ranking=18)]

[    ProgrammingLang(name='Python', ranking=7),
     ProgrammingLang(name='Javascript', ranking=8),
     ProgrammingLang(name='Ruby', ranking=14),
     ProgrammingLang(name='Swift', ranking=18),
     ProgrammingLang(name='Lisp', ranking=23),
     ProgrammingLang(name='Scala', ranking=31)]

Java API也使用了策略設(shè)計(jì)模式。java.util.Comparator是一個(gè)接口,包含一個(gè)compare()方法,該方法本質(zhì)上是一個(gè)策略,可傳給排序方法,比如Collections.sort和Arrays.sort(請(qǐng)參考網(wǎng)頁[t.cn/RqrB5o9])。

應(yīng)用案例

策略模式是一種非常通用的設(shè)計(jì)模式,可應(yīng)用的場(chǎng)景很多。一般來說,不論何時(shí)希望動(dòng)態(tài)、透明地應(yīng)用不同算法,策略模式都是可行之路。這里所說不同算法的意思是,結(jié)果相同但實(shí)現(xiàn)方案不同的一類算法。這意味著算法結(jié)果應(yīng)該是完全一致的,但每種實(shí)現(xiàn)都有不同的性能和代碼復(fù)雜性(舉例來說,對(duì)比一下順序查找和二分查找)。

我們已看到Python和Java如何使用策略模式來支持不同的排序算法。然而,策略模式并不限于排序問題,也可用于創(chuàng)建各種不同的資源過濾器(身份驗(yàn)證、H志記錄、數(shù)據(jù)壓縮和加密等),請(qǐng)參考網(wǎng)頁[t.cn/RqrBchI]。

策略模式的另一個(gè)應(yīng)用是創(chuàng)建不同的樣式表現(xiàn),為了實(shí)現(xiàn)可移植性(例如,不同平臺(tái)之間斷行的不同)或動(dòng)態(tài)地改變數(shù)據(jù)的表現(xiàn)。

另一個(gè)值得一提的應(yīng)用是模擬;例如模擬機(jī)器人,一些機(jī)器人比另一些更有攻擊性,一些機(jī)器人速度更快,等等。機(jī)器人行為中的所有不同之處都可以使用不同的策略來建模(請(qǐng)參考網(wǎng)頁[t.cn/RqrBf2q])。

實(shí)現(xiàn)

關(guān)于策略模式的實(shí)現(xiàn)沒有太多可說的。在函數(shù)非一等公民的語言中,每個(gè)策略都要用一個(gè)不同的類來實(shí)現(xiàn)。Wikipedia頁面中有UML圖展示了這一點(diǎn)(請(qǐng)參考網(wǎng)頁[t.cn/RqrBMhW])。在Python中,我們可以把函數(shù)看作是普通的變量,這就簡化了策略模式的實(shí)現(xiàn)。

假設(shè)我們要實(shí)現(xiàn)一個(gè)算法來檢測(cè)在一個(gè)字符串中是否所有字符都是唯一的。例如,如果輸入字符串dream,算法應(yīng)返回true,因?yàn)闆]有字符是重復(fù)的。如果輸入字符串pizza,算法應(yīng)返回false,因?yàn)樽帜竮出現(xiàn)了兩次。注意,重復(fù)字符不一定是連續(xù)的,并且字符串也不一定是一個(gè)合法單詞。對(duì)于字符串1r2a3ae,算法也應(yīng)該返回false,因?yàn)槠渲凶帜竌出現(xiàn)了兩次。

在仔細(xì)考慮問題之后,我們提出一種實(shí)現(xiàn):對(duì)字符串進(jìn)行排序并逐對(duì)比較所有字符。我們首先實(shí)現(xiàn)pairs()函數(shù),它會(huì)返回所有相鄰字符對(duì)的一個(gè)序列seq。

def pairs(seq):
    n = len(seq)
    for i in range(n):
        yield seq[i], seq[(i + 1) % n]

接下來,實(shí)現(xiàn)allUniqueSort()函數(shù)。它接受一個(gè)字符串參數(shù)s,如果該字符串中所有字符都是唯一的,則返回True;否則,返回False。為演示策略模式,我們進(jìn)行一些簡化,假設(shè)這個(gè)算法的伸縮性不好,對(duì)于不超過5個(gè)字符的字符串才能工作良好。對(duì)于更長的字符串,通過捕入一條sleep語旬來模擬速度減緩。

SLOW = 3 # 單位為秒
LIMIT = 5 # 字符數(shù)
WARNING = 'too bad, you picked the slow algorithm :('

def allUniqueSort(s):
    if len(s) > LIMIT:
        print(WARNING)
        time.sleep(SLOW)
    srtStr = sorted(s)
    for (c1, c2) in pairs(srtStr):
        if c1 == c2:
            return False
    return True

我們對(duì)allUniqueSort()的性能并不滿意,所以嘗試考慮優(yōu)化的方式。一段時(shí)間之后,我們提出一個(gè)新算法allUniqueSet(),消除排序的需要。在這里,我們使用一個(gè)集合來實(shí)現(xiàn)算法。如果正在檢測(cè)的字符已經(jīng)被捕入到集合中,則意味著字符串中并非所有字符都是唯一的。

def allUniqueSet(s):
    if len(s) < LIMIT:
        print(WARNING)
        time.sleep(SLOW)

    return True if len(set(s)) == len(s) else False

不幸的是,allUniqueSet()雖然沒有伸縮性問題,但出于一些奇怪的原因,它檢測(cè)短字符串的性能比allUniqueSort()更差。這樣的話我們能做點(diǎn)什么呢?沒關(guān)系,我們可以保留兩個(gè)算法,并根據(jù)待檢測(cè)字符串的長度來選擇最合適的那個(gè)算法。函數(shù)allUnique()接受一個(gè)輸入字符串s和一個(gè)策略函數(shù)strategy,在這里是allUniqueSort()和allUniqueSet()中的一個(gè)。函數(shù)allUnique執(zhí)行輸入的策略,并向調(diào)用者返回結(jié)果。

使用main()函數(shù)可以執(zhí)行以下操作。

  • 輸入待檢測(cè)字符唯一性的單詞
  • 選擇要使用的策略

該函數(shù)還進(jìn)行了一些基本的錯(cuò)誤處理,并讓用戶能夠正常退出程序。

def main():
    while True:
        word = None
        while not word:
            word = input('Insert word (type quit to exit)> ')

            if word == 'quit':
                print('bye')
                return

            strategy_picked = None
            strategies = { '1': allUniqueSet, '2': allUniqueSort }
            while strategy_picked not in strategies.keys():
                strategy_picked = input('Choose strategy: [1] Use a set, [2] Sort and pair> ')

                try:
                    strategy = strategies[strategy_picked]
                    print('allUnique({}): {}'.format(word, allUnique(word, strategy)))
                except KeyError as err:
                    print('Incorrect option: {}'.format(strategy_picked))
            print()

下面是該示例的完整代碼(文件strategy.py)。

import time

SLOW = 3                        # in seconds
LIMIT = 5                       # in characters
WARNING = 'too bad, you picked the slow algorithm :('

def pairs(seq):
    n = len(seq)
    for i in range(n):
        yield seq[i], seq[(i + 1) % n]

def allUniqueSort(s):
   if len(s) > LIMIT:
       print(WARNING)
       time.sleep(SLOW)
   srtStr = sorted(s)
   for (c1, c2) in pairs(srtStr):
       if c1 == c2:
           return False
   return True

def allUniqueSet(s):
    if len(s) < LIMIT:
        print(WARNING)
        time.sleep(SLOW)
    return True if len(set(s)) == len(s) else False

def allUnique(s, strategy):
    return strategy(s)

def main():
    while True:
        word = None
        while not word:
            word = input('Insert word (type quit to exit)> ')

            if word == 'quit':
                print('bye')
                return

            strategy_picked = None
            strategies = { '1': allUniqueSet, '2': allUniqueSort }
            while strategy_picked not in strategies.keys():
                strategy_picked = input('Choose strategy: [1] Use a set, [2] Sort and pair> ')

                try:
                    strategy = strategies[strategy_picked]
                    print('allUnique({}): {}'.format(word, allUnique(word, strategy)))
                except KeyError as err:
                    print('Incorrect option: {}'.format(strategy_picked))
            print()

if __name__ == '__main__':
    main()

第一個(gè)單詞(ballon)多于5個(gè)字符,并且不是所有字符都是唯一的。這種情況下,兩個(gè)算法都返回了正確結(jié)果(False),但allUniqueSort()更慢,用戶也收到了警告。

第二個(gè)單詞(bye)少于5個(gè)字符,并且所有字符都是唯一的。再一次,兩個(gè)算法都返回了期望的結(jié)果(True),但這一次,allUniqueSet()更慢,用戶也再一次收到警告。

最后一個(gè)單詞(h)是一個(gè)特殊案例。allUniqueSet()運(yùn)行慢,處理正確,返回期望的True;算法allUniqueSort()返回超快,但結(jié)果錯(cuò)誤。你能明臼為什么嗎?作為練習(xí),請(qǐng)修復(fù)allUniqueSort()算法。你也許想禁止處理單字符的單詞,我覺得這樣挺不錯(cuò)(相比返回一個(gè)錯(cuò)誤結(jié)果,這樣更好)。

通常,我們想要使用的策略不應(yīng)該由用戶來選擇。策略模式的要點(diǎn)是可以透明地使用不同的算法。修改一下代碼,使得程序始終選擇更快的算法。

我們的代碼有兩種常見用戶。一種是最終用戶,他們不應(yīng)該關(guān)心代碼中發(fā)生的事情。為達(dá)到這個(gè)效果,我們可以遵循前一段給出的提示來實(shí)現(xiàn)。另一類用戶是其他開發(fā)人員。假設(shè)我們想創(chuàng)建一個(gè)供其他開發(fā)人員使用的API。如何做到讓他們不用關(guān)心策略模式?一個(gè)提示是考慮在一個(gè)公用類(例如,AllUnique)中封裝兩個(gè)函數(shù)。這樣,其他開發(fā)人員只需要?jiǎng)?chuàng)建一個(gè)AllUnique類實(shí)例,并執(zhí)行單個(gè)方法,例如test()。在這個(gè)方法中需要做些什么呢?

小結(jié)

本章中,我們學(xué)習(xí)了策略設(shè)計(jì)模式。策略模式通常用在我們希望對(duì)同一個(gè)問題透明地使用多種方案時(shí)。如果并不存在針對(duì)所有輸入數(shù)據(jù)和所有情況的完美算法,那么我們可以使用策略模式,動(dòng)態(tài)地決定在每種情況下應(yīng)使用哪種算法。現(xiàn)實(shí)中,在我們想趕去機(jī)場(chǎng)乘飛機(jī)時(shí)會(huì)使用策略模式。

Python使用策略模式讓客戶端代碼決定如何對(duì)一個(gè)數(shù)據(jù)結(jié)構(gòu)中的元素進(jìn)行排序。我們看到了一個(gè)例子,基于TIOBE指數(shù)排行榜對(duì)編程語言進(jìn)行排序。

策略設(shè)計(jì)模式的使用并不限于排序領(lǐng)域。加密、壓縮、H志記錄及其他資源處理的領(lǐng)域都可以使用策略模式來提供不同的數(shù)據(jù)處理方式。可移植性是策略模式的另一個(gè)用武之地。模擬也是另一個(gè)策略模式適用的領(lǐng)域。

通過實(shí)現(xiàn)兩種不同算法來檢測(cè)一個(gè)單詞中所有字符的唯一性,我們學(xué)習(xí)了Python如何因其具有一等函數(shù)而簡化了策略模式的實(shí)現(xiàn)。

在本書的第16章中,我們將學(xué)習(xí)模板模式。該模式用于抽取一個(gè)算法的通用部分,從而提高代碼復(fù)用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評(píng)論 6 540
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,275評(píng)論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,904評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,368評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,736評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,919評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,481評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,235評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,427評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,656評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評(píng)論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,160評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,380評(píng)論 2 379

推薦閱讀更多精彩內(nèi)容

  • 前言 設(shè)計(jì)模式是我們實(shí)際應(yīng)用開發(fā)中必不可缺的,對(duì)設(shè)計(jì)模式的理解有助于我們寫出可讀性和擴(kuò)展更高的應(yīng)用程序。雖然設(shè)計(jì)模...
    丶legend閱讀 557評(píng)論 0 3
  • 第5章 引用類型(返回首頁) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,263評(píng)論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,818評(píng)論 18 139
  • usingUnityEngine; usingSystem.Collections; usingUnityEngi...
    胤醚貔貅閱讀 977評(píng)論 0 2
  • 有時(shí)我們寧愿相信一個(gè)男人壓力太大、太累、太自卑、太敏感。有童年陰影或者太愛前女友,卻不愿承認(rèn)一個(gè)簡單的事實(shí)。是的,...
    青羅裳閱讀 368評(píng)論 0 3