設(shè)計(jì)模式系列10--裝飾者模式

image

大部分公司都有銷(xiāo)售團(tuán)隊(duì),假設(shè)老板給你布置了一個(gè)任務(wù)氮唯,讓你按照下面的要求開(kāi)發(fā)一套程序來(lái)計(jì)算銷(xiāo)售團(tuán)隊(duì)每個(gè)月的工資玖详。

  • 每個(gè)人當(dāng)月業(yè)務(wù)獎(jiǎng)金 = 當(dāng)月銷(xiāo)售額 * 3%
  • 每個(gè)人的累積獎(jiǎng)金 = 總的回款額 * 0.1%
  • 銷(xiāo)售經(jīng)理的團(tuán)隊(duì)獎(jiǎng)金 = 團(tuán)隊(duì)總銷(xiāo)售額 * 1%

每個(gè)人的工資就是基本工資加上獎(jiǎng)金东揣,那么按照常規(guī)模式我們來(lái)看下如何讓實(shí)現(xiàn)眼俊。

#import "calculateBonus.h"

@implementation calculateBonus

-(NSInteger)calculateSalary:(NSInteger)monthSales  sumSales:(NSInteger)sumSales isManager:(BOOL)manager{
    //基本工資都是8000
    NSInteger salary = 8000;
    salary += [self monthBonus:monthSales];
    salary += [self sumBonus:sumSales];
    if (manager) {
        salary += [self groupBonus];
    }

    return salary;
    
}


//當(dāng)月獎(jiǎng)金
-(NSInteger)monthBonus:(NSInteger)monthSales{
    return monthSales * 0.003;
}


//累積獎(jiǎng)金
-(NSInteger)sumBonus:(NSInteger)sumSales{
    return  sumSales * 0.001;
}

//團(tuán)隊(duì)獎(jiǎng)金
-(NSInteger)groupBonus{
    //簡(jiǎn)單起見(jiàn),團(tuán)隊(duì)的銷(xiāo)售總額設(shè)置為100000
    return 100000 * 0.01;
}
@end

測(cè)試下:

calculateBonus *calculate = [calculateBonus new];
NSInteger salary1 = [calculate calculateSalary:12222 sumSales:12000 isManager:YES];
NSLog(@"經(jīng)理工資:%zd", salary1);

NSInteger salary2 = [calculate calculateSalary:21333 sumSales:23111 isManager:NO];
NSLog(@"員工甲:%zd", salary2);

NSInteger salary3 = [calculate calculateSalary:22113 sumSales:11222 isManager:NO];
NSLog(@"員工乙:%zd", salary3);

輸出:

2016-12-14 08:57:58.600 裝飾者模式[64313:1880733] 經(jīng)理工資:9048
2016-12-14 08:57:58.601 裝飾者模式[64313:1880733] 員工甲:8086
2016-12-14 08:57:58.601 裝飾者模式[64313:1880733] 員工乙:8077
Program ended with exit code: 0

看起來(lái)運(yùn)行良好悲酷,好套菜,該來(lái)的還是來(lái)了,該需求设易。

現(xiàn)在要增加一個(gè)環(huán)比獎(jiǎng)金:就是本月銷(xiāo)售額比上月又增加逗柴,然后達(dá)到一定比例,就會(huì)有獎(jiǎng)金顿肺,增加越多戏溺,獎(jiǎng)金比率越高。你說(shuō)這還不簡(jiǎn)單屠尊,再加一個(gè)環(huán)比獎(jiǎng)金計(jì)算方法不就是了旷祸。那么如果工資計(jì)算的方式也換了呢?不同級(jí)別的人員或者員工的計(jì)算獎(jiǎng)金的方式也換了呢讼昆?

假設(shè)

  • 甲的總工資 = 基本工資 + 當(dāng)月銷(xiāo)售獎(jiǎng)金 + 環(huán)比獎(jiǎng)金

  • 乙的工資 = 基本工資 + 環(huán)比獎(jiǎng)金

  • 丙的工資 = 基本工資 + 當(dāng)月銷(xiāo)售獎(jiǎng)金

  • 丁的工資 = 基本工資 + 環(huán)比獎(jiǎng)金 + 團(tuán)隊(duì)獎(jiǎng)金

后面再給你制定十幾種不同的計(jì)算方式托享,崩潰了沒(méi)有?按照上面的寫(xiě)法浸赫,那么每一種總工資計(jì)算方式你都要寫(xiě)一種方法闰围,再假設(shè)這些人的總工資計(jì)算方式每個(gè)季度還會(huì)有調(diào)整,你怎么辦掺炭,接著改?

仔細(xì)分析下上面的需求凭戴,總工資的計(jì)算有兩部分:基本工資加上各種獎(jiǎng)金涧狮,基本工資是固定的,麻煩的地方就在于獎(jiǎng)金的計(jì)算方式是動(dòng)態(tài)變化的,有各種各樣的組合方式者冤。按照設(shè)計(jì)模式的思想:封裝變化肤视,這里變化的部分是獎(jiǎng)金的組合方式,那么我們就把這部分封裝起來(lái)涉枫。

我們可以采取這樣的方式邢滑,把每張獎(jiǎng)金的計(jì)算方式都單獨(dú)成類(lèi),然后需要用到哪種獎(jiǎng)金計(jì)算愿汰,就把這個(gè)獎(jiǎng)金計(jì)算和基本工資組合起來(lái)困后,需要多少種獎(jiǎng)金計(jì)算方式,就組合多少種衬廷。這樣實(shí)現(xiàn)起來(lái)摇予,是不是非常靈活?以后你想修改或者增加減少獎(jiǎng)金計(jì)算方式吗跋,只需要修改或者增加減少一個(gè)獎(jiǎng)金計(jì)算方式就可以了侧戴,至于每個(gè)人的總工資計(jì)算方式各不相同,就更簡(jiǎn)單了跌宛,交給客戶(hù)端自由組合酗宋。

總結(jié)起來(lái)就是如下三個(gè)要求:

  • 獎(jiǎng)金計(jì)算方式要靈活,可以動(dòng)態(tài)增加或者減少

  • 可以動(dòng)態(tài)組合獎(jiǎng)金計(jì)算方式

要實(shí)現(xiàn)上面的功能疆拘,就要清楚我們今天的豬腳:裝飾器模式蜕猫。

下面來(lái)認(rèn)識(shí)下這位仁兄


定義

動(dòng)態(tài)地給一個(gè)對(duì)象添加一些額外的職責(zé)。就增加功能來(lái)說(shuō), 裝飾模式比生成子類(lèi)更為靈活入问。

一般我們?cè)诮o一個(gè)原本的類(lèi)添加功能的時(shí)候丹锹,都會(huì)想到使用繼承,在原有的類(lèi)上擴(kuò)展新的功能芬失,但是繼承有一個(gè)非常大的缺點(diǎn):和父類(lèi)耦合性太高楣黍。如果后續(xù)需要添加或者減少功能,就不得不每次都要修改子類(lèi)棱烂,而且如果修改了父類(lèi)租漂,對(duì)子類(lèi)的影響也非常大。

所以我們一般優(yōu)先考慮使用組合來(lái)實(shí)現(xiàn)功能的擴(kuò)展颊糜,這也是設(shè)計(jì)模式的一個(gè)原則:多用組合哩治,少用繼承。裝飾器模式就是實(shí)現(xiàn)組合功能的一種方式衬鱼,它可以透明的給原本的類(lèi)增加或者減少功能业筏,而且可以把多個(gè)功能組合在一起,他不會(huì)改變?cè)蓄?lèi)的功能鸟赫,只是在原來(lái)功能的基礎(chǔ)上加上一些新功能蒜胖,而這些操作被裝飾對(duì)象是毫不知情的消别。

比如上面的計(jì)算總工資,原有的對(duì)象是基本工資台谢,但是需要在基本工資的基礎(chǔ)上加上各種獎(jiǎng)金寻狂,也就是給基本工資擴(kuò)展了功能,但是基本工資這個(gè)原有功能是不會(huì)改變的朋沮,只是給他加上了各種各樣的獎(jiǎng)金蛇券,豐富了它的功能,最后算出來(lái)的還是工資樊拓,也就是保持原有的類(lèi)型(整數(shù)型)不改變纠亚,這點(diǎn)要切記。


UML結(jié)構(gòu)如及說(shuō)明

image

實(shí)現(xiàn)裝飾器模式要注意如下幾點(diǎn):

  1. 接 口 的 一 致 性

    裝飾對(duì)象的接口必須與它所裝飾的 C o m p o n e n t 的 接 口 是 一 致 的 , 因 此 ,
    所有的 concreteDecorator 類(lèi)必須有一個(gè)公共的父類(lèi)

  2. 省略抽象的 D e c o r a t o r 類(lèi)

    當(dāng)你僅需要添加一個(gè)職責(zé)時(shí),沒(méi)有必要定義抽象 D e c o r a t o r 類(lèi)骑脱。 你常常需要處理現(xiàn)存的類(lèi)層次結(jié)構(gòu)而不是設(shè)計(jì)一個(gè)新系統(tǒng),這時(shí)你可以把 D e c o r a t o r 向 C o m p o n e n t 轉(zhuǎn)發(fā)請(qǐng)求的職責(zé)合并到 C o n c r e t e D e c o r a t o r 中菜枷。

  3. 保持 C o m p o n e n t 類(lèi) 的 簡(jiǎn) 單 性

    為 了 保 證 接 口 的 一 致 性 , 組 件 和 裝 飾 必 須 有 一 個(gè) 公 共 的 C o m p o n e n t 父類(lèi)。因此保持這個(gè)類(lèi)的簡(jiǎn)單性是很重要的叁丧;即啤誊,它應(yīng)集中于定義接口而不是存儲(chǔ)數(shù)據(jù)。對(duì)數(shù)據(jù)表示的定義應(yīng)延遲到子類(lèi)中拥娄,否則 C o m p o n e n t 類(lèi) 會(huì) 變 得 過(guò) 于 復(fù) 雜 和 龐 大 , 因 而難以大量使用蚊锹。賦予 C o m p o n e n t太 多 的 功 能 也 使 得 , 具 體 的 子 類(lèi) 有 一 些 它 們 并 不 需 要 的 功 能的可能性大大增加。

  4. 改 變 對(duì) 象 外 殼 與 改 變 對(duì) 象 內(nèi) 核

    我們可以將 D e c o r a t o r 看 作 一 個(gè) 對(duì) 象 的 外 殼 , 它 可 以 改 變這個(gè)對(duì)象的行為稚瘾。另外一種方法是改變對(duì)象的內(nèi)核牡昆。例如, S t r a t e g y 模 式 就 是 一 個(gè) 用 于 改變內(nèi)核的很好的模式。
    當(dāng) C o m p o n e n t 類(lèi) 原 本 就 很 龐 大 時(shí) , 使 用 D e c o r a t o r 模 式 代 價(jià) 太 高 , S t r a t e g y模 式 相 對(duì) 更 好 一 些摊欠。在 S t r a t e g y 模式中丢烘,組件將它的一些行為轉(zhuǎn)發(fā)給一個(gè)獨(dú)立的策略對(duì)象,我們可以替換s t r a t e g y 對(duì)象些椒,從而改變或擴(kuò)充組件的功能播瞳。

image

代碼實(shí)現(xiàn)

1、定義抽象基類(lèi)

先定義一個(gè)抽象基類(lèi)免糕,工資類(lèi)和獎(jiǎng)金計(jì)算方式類(lèi)都繼承自這個(gè)類(lèi)赢乓,該類(lèi)定義了一個(gè)公開(kāi)接口,用于計(jì)算獎(jiǎng)金

#import <Foundation/Foundation.h>

@interface component : NSObject
-(NSInteger)calculateSalary:(NSInteger)monthSales  sumSales:(NSInteger)sumSales;
@end

=================

2石窑、定義工資類(lèi)(被裝飾對(duì)象)

#import "component.h"

@interface concreteComponent : component

@end

======================

//被裝飾對(duì)象牌芋,基本工資

#import "concreteComponent.h"

@implementation concreteComponent

-(NSInteger)calculateSalary:(NSInteger)monthSales  sumSales:(NSInteger)sumSales{
    //基本工資8000
    return 8000;
}

@end

3、定義抽象裝飾器

定義一個(gè)抽象裝飾器松逊,繼承自抽象基類(lèi)component躺屁,每個(gè)具體的裝飾器繼承自該類(lèi),該類(lèi)主要做一些初始化工作


#import "component.h"

@interface Decorator : component
@property(strong,nonatomic)component *components;
- (instancetype)initWithComponet:(component *)component;
@end

=================

#import "Decorator.h"

@implementation Decorator
- (instancetype)initWithComponet:(component *)component
{
    self = [super init];
    if (self) {
        self.components = component;
    }
    return self;
}

-(NSInteger)calculateSalary:(NSInteger)monthSales sumSales:(NSInteger)sumSales{
    return [self.components calculateSalary:monthSales sumSales:sumSales];
}
@end


4经宏、具體裝飾器

每月銷(xiāo)售獎(jiǎng)金裝飾器

#import "Decorator.h"

@interface monthBonusDecorator : Decorator

@end

==================


#import "monthBonusDecorator.h"

@implementation monthBonusDecorator

-(NSInteger)calculateSalary:(NSInteger)monthSales sumSales:(NSInteger)sumSales{
    NSInteger salary = [self.components calculateSalary:monthSales sumSales:sumSales];
    NSInteger bonus = monthSales * 0.03;
    NSLog(@"當(dāng)月銷(xiāo)售獎(jiǎng)金:%zd", bonus);
    return salary += bonus;
}
@end

累積獎(jiǎng)金裝飾器

#import "Decorator.h"

@interface sumBonusDecatorator : Decorator

@end

================

#import "sumBonusDecatorator.h"

@implementation sumBonusDecatorator

-(NSInteger)calculateSalary:(NSInteger)monthSales sumSales:(NSInteger)sumSales{
    NSInteger salary = [self.components calculateSalary:monthSales sumSales:sumSales];
    NSInteger bonus = sumSales * 0.01;
    NSLog(@"累積銷(xiāo)售獎(jiǎng)金:%zd", bonus);
    return salary += bonus;
}

@end

團(tuán)隊(duì)獎(jiǎng)金裝飾器

#import "Decorator.h"

@interface groupBonusDecorator : Decorator

@end

=================

#import "groupBonusDecorator.h"

@implementation groupBonusDecorator
-(NSInteger)calculateSalary:(NSInteger)monthSales sumSales:(NSInteger)sumSales{
    NSInteger salary = [self.components calculateSalary:monthSales sumSales:sumSales];
    NSInteger bonus = 100000 * 0.01;
    NSLog(@"團(tuán)隊(duì)獎(jiǎng)金:%zd", bonus);
    return salary += bonus;
}
@end

5犀暑、測(cè)試

 //基本工資熄捍,被裝飾對(duì)象
        component *c1 = [concreteComponent new];
        
        //裝飾器
        Decorator *d1 = [[monthBonusDecorator alloc]initWithComponet:c1];
        Decorator *d2 = [[sumBonusDecatorator alloc]initWithComponet:d1];
        NSInteger salary1 = [d2 calculateSalary:10000 sumSales:12212];
        NSLog(@"\n獎(jiǎng)金組合方式:當(dāng)月銷(xiāo)售獎(jiǎng)金 + 累積銷(xiāo)售獎(jiǎng)金 \n 總工資 = %zd", salary1);
        
        NSLog(@"\n=============================================================================");
        
        Decorator *d3 = [[monthBonusDecorator alloc]initWithComponet:c1];
        Decorator *d4 = [[sumBonusDecatorator alloc]initWithComponet:d3];
        Decorator *d5 = [[groupBonusDecorator alloc]initWithComponet:d4];
        NSInteger salary2 = [d5 calculateSalary:12100 sumSales:12232];
        NSLog(@"\n獎(jiǎng)金組合方式:當(dāng)月銷(xiāo)售獎(jiǎng)金 + 累積銷(xiāo)售獎(jiǎng)金 + 團(tuán)隊(duì)獎(jiǎng)金 \n 總工資 = %zd", salary2);
        
        
        NSLog(@"\n=============================================================================");

        Decorator *d6 = [[monthBonusDecorator alloc]initWithComponet:c1];
        Decorator *d7 = [[groupBonusDecorator alloc]initWithComponet:d6];
        NSInteger salary3 = [d7 calculateSalary:23111 sumSales:231111];
        NSLog(@"\n獎(jiǎng)金組合方式:當(dāng)月銷(xiāo)售獎(jiǎng)金 + 團(tuán)隊(duì)獎(jiǎng)金 \n 總工資 = %zd", salary3);


輸出如下

2016-12-14 10:34:31.280 裝飾者模式[64586:1944336] 當(dāng)月銷(xiāo)售獎(jiǎng)金:300
2016-12-14 10:34:31.280 裝飾者模式[64586:1944336] 累積銷(xiāo)售獎(jiǎng)金:122
2016-12-14 10:34:31.280 裝飾者模式[64586:1944336] 
獎(jiǎng)金組合方式:當(dāng)月銷(xiāo)售獎(jiǎng)金 + 累積銷(xiāo)售獎(jiǎng)金 
 總工資 = 8422

=============================================================================
2016-12-14 10:34:31.280 裝飾者模式[64586:1944336] 當(dāng)月銷(xiāo)售獎(jiǎng)金:363
2016-12-14 10:34:31.280 裝飾者模式[64586:1944336] 累積銷(xiāo)售獎(jiǎng)金:122
2016-12-14 10:34:31.280 裝飾者模式[64586:1944336] 團(tuán)隊(duì)獎(jiǎng)金:1000
2016-12-14 10:34:31.280 裝飾者模式[64586:1944336] 
獎(jiǎng)金組合方式:當(dāng)月銷(xiāo)售獎(jiǎng)金 + 累積銷(xiāo)售獎(jiǎng)金 + 團(tuán)隊(duì)獎(jiǎng)金 
 總工資 = 9485

=============================================================================
2016-12-14 10:34:31.281 裝飾者模式[64586:1944336] 當(dāng)月銷(xiāo)售獎(jiǎng)金:693
2016-12-14 10:34:31.281 裝飾者模式[64586:1944336] 團(tuán)隊(duì)獎(jiǎng)金:1000
2016-12-14 10:34:31.281 裝飾者模式[64586:1944336] 
獎(jiǎng)金組合方式:當(dāng)月銷(xiāo)售獎(jiǎng)金 + 團(tuán)隊(duì)獎(jiǎng)金 
 總工資 = 9693

6、小結(jié)

從上面的測(cè)試可以看出母怜,不管是使用何種獎(jiǎng)金組合方式,只需要調(diào)用對(duì)應(yīng)的裝飾器即可缚柏,非常靈活苹熏。通過(guò)上面的代碼我們看到,裝飾器是一層層包裹的币喧,基本工資被月工資裝飾器包裹轨域,月工資裝飾器被累積獎(jiǎng)金裝飾器包裹,累積裝飾器被團(tuán)隊(duì)獎(jiǎng)金裝飾器包裹杀餐,當(dāng)調(diào)用計(jì)算獎(jiǎng)金的公式的時(shí)候干发,就會(huì)按照順序?qū)訉舆f歸調(diào)用每個(gè)裝飾器的功能,到最后算出總工資史翘,我們來(lái)用示意圖看看調(diào)用過(guò)程枉长。

由于每個(gè)裝飾器之間是完全獨(dú)立的,所以我們可以使用任何我們想要的方式去組合這些裝飾器琼讽,比如多次重復(fù)調(diào)用同一個(gè)裝飾器必峰,調(diào)換裝飾器的順序等等。

image

適用性

在如下情況可以考慮使用對(duì)象組合

  • 在不影響其他對(duì)象的情況下,以動(dòng)態(tài)钻蹬、透明的方式給單個(gè)對(duì)象添加職責(zé)吼蚁。

  • 處理那些可以撤消的職責(zé)。

  • 當(dāng)不能采用生成子類(lèi)的方法進(jìn)行擴(kuò)充時(shí)
    一種情況是问欠,可能有大量獨(dú)立的擴(kuò)展肝匆,為支持每一種組合將產(chǎn)生大量的子類(lèi),使得子類(lèi)數(shù)目呈爆炸性增長(zhǎng)顺献。另一種情況可能是因?yàn)轭?lèi)定義被隱藏旗国,或類(lèi)定義不能用于生成子類(lèi)。


優(yōu)缺點(diǎn)

  1. 比繼 承 更 靈 活

    與 對(duì) 象 的 靜 態(tài) 繼 承 ( 多 重 繼 承 ) 相 比 , D e c o r a t o r 模 式 提 供 了 更 加
    靈活的向?qū)ο筇砑勇氊?zé)的方式滚澜〈植郑可以用添加和分離的方法,用裝飾在運(yùn)行時(shí)刻增加和刪除職 責(zé)。相比之下,繼承機(jī)制要求為每個(gè)添加的職責(zé)創(chuàng)建一個(gè)新的子類(lèi)设捐。這會(huì)產(chǎn)生許多新的類(lèi),并且會(huì)增加系統(tǒng)的復(fù)雜度借浊。此外,為一 個(gè)特定的 C o m p o n e n t 類(lèi) 提 供 多 個(gè) 不 同 的 D e c o r a t o r 類(lèi) , 這 就 使 得 你 可 以 對(duì) 一 些 職 責(zé) 進(jìn) 行 混 合 和 匹配。
    使用 D e c o r a t o r 模式可以很容易地重復(fù)添加一個(gè)特性萝招。

  2. 避 免 了高層次類(lèi) 有 太 多 的 特 征

    D e c o r a t o r模 式 提 供 了 一 種 “ 即 用 即 付 ” 的 方 法來(lái)添加職責(zé)蚂斤。它并不試圖在一個(gè)復(fù)雜的可定制的類(lèi)中支持所有可預(yù)見(jiàn)的特征,相反槐沼,你可 以定義一個(gè)簡(jiǎn)單的類(lèi)曙蒸,并且用 D e c o r a t o r 類(lèi) 給 它 逐 漸 地 添 加 功 能 捌治。 可 以 從 簡(jiǎn) 單 的 部 件 組 合 出 復(fù) 雜的功能。這樣纽窟,應(yīng)用程序不必為不需要的特征付出代價(jià)肖油。同時(shí)也更易于不依賴(lài)于 D e c o r a t o r 所擴(kuò)展(甚至是不可預(yù)知的擴(kuò)展)的類(lèi)而獨(dú)立地定義新類(lèi)型的 D e c o r a t o r 。 擴(kuò) 展 一 個(gè) 復(fù) 雜 類(lèi) 的 時(shí)候,很可能會(huì)暴露與添加的職責(zé)無(wú)關(guān)的細(xì)節(jié)臂港。

  3. 產(chǎn)生 許 多 小 對(duì) 象

    采用 D e c o r a t o r 模 式 進(jìn) 行 系 統(tǒng) 設(shè) 計(jì) 往 往 會(huì) 產(chǎn) 生 許 多 看 上 去 類(lèi) 似 的 小 對(duì) 象 , 這些對(duì)象僅僅在他們相互連接的方式上有所不同,而不是它們的類(lèi)或是它們的屬性值有所不 同森枪。盡管對(duì)于那些了解這些系統(tǒng)的人來(lái)說(shuō),很容易對(duì)它們進(jìn)行定制,但是很難學(xué)習(xí)這些系統(tǒng), 排錯(cuò)也很困難。


裝飾器和AOP

關(guān)于面向切換編程的具體解釋看這里

百度百科AOP解釋

AOP一般用來(lái)實(shí)現(xiàn)如下功能:日志記錄审孽,性能統(tǒng)計(jì)县袱,安全控制,事務(wù)處理佑力,異常處理等等式散。將日志記錄,性能統(tǒng)計(jì)打颤,安全控制暴拄,事務(wù)處理,異常處理等代碼從業(yè)務(wù)邏輯代碼中劃分出來(lái)编饺,通過(guò)對(duì)這些行為的分離揍移,我們希望可以將它們獨(dú)立到非業(yè)務(wù)邏輯的方法中,進(jìn)而改變這些行為的時(shí)候不影響業(yè)務(wù)邏輯的代碼反肋。

看上面的描述就知道那伐,裝飾器就是一個(gè)很好實(shí)現(xiàn)AOP的方式,因?yàn)檠b飾器就是在不改變?cè)泄δ艿那疤嵯聦?duì)其進(jìn)行透明擴(kuò)展的石蔗。

我們目前有一個(gè)鴨子類(lèi)罕邀,實(shí)現(xiàn)呱呱叫的一個(gè)方法,現(xiàn)在我希望在不改變?cè)泄δ艿那闆r下养距,統(tǒng)計(jì)鴨子叫了多少次诉探,這就是AOP中的日志記錄功能,我們可以使用裝飾器模式來(lái)實(shí)現(xiàn)棍厌,具體代碼我就不貼了肾胯,直接看最后的demo。


裝飾器在iOS中的運(yùn)用

我們應(yīng)該用過(guò)一些圖片處理app耘纱,可以給圖片加上各種各樣的濾鏡或者裁剪旋轉(zhuǎn)圖片等等功能敬肚,其實(shí)這些也可以使用裝飾器來(lái)實(shí)現(xiàn),可以把每個(gè)功能都實(shí)現(xiàn)為一個(gè)裝飾器束析,然后用戶(hù)選擇使用什么功能艳馒,就給圖片加上對(duì)應(yīng)的裝飾器去做處理,這樣做是不是非常靈活?

其實(shí)在iOS里面已經(jīng)為我們提供了類(lèi)似裝飾器模式的功能的方法:category弄慰。category也可以透明的為一個(gè)類(lèi)添加方法第美,下面我就使用一個(gè)小demo來(lái)演示如何使用category和裝飾者模式分別來(lái)實(shí)現(xiàn)圖片的選擇和陰影效果。具體見(jiàn)demo陆爽。


demo下載

裝飾者模式Demo

鴨子叫聲計(jì)數(shù)器Demo

裝飾者模式和category Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末什往,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子慌闭,更是在濱河造成了極大的恐慌恶守,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贡必,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡庸毫,警方通過(guò)查閱死者的電腦和手機(jī)仔拟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)飒赃,“玉大人利花,你說(shuō)我怎么就攤上這事≡丶眩” “怎么了炒事?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蔫慧。 經(jīng)常有香客問(wèn)我挠乳,道長(zhǎng),這世上最難降的妖魔是什么姑躲? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任睡扬,我火速辦了婚禮,結(jié)果婚禮上黍析,老公的妹妹穿的比我還像新娘卖怜。我一直安慰自己,他們只是感情好阐枣,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布马靠。 她就那樣靜靜地躺著,像睡著了一般蔼两。 火紅的嫁衣襯著肌膚如雪甩鳄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天额划,我揣著相機(jī)與錄音娩贷,去河邊找鬼。 笑死锁孟,一個(gè)胖子當(dāng)著我的面吹牛彬祖,可吹牛的內(nèi)容都是我干的茁瘦。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼储笑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼甜熔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起突倍,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤腔稀,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后羽历,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體焊虏,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年秕磷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诵闭。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡澎嚣,死狀恐怖疏尿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情易桃,我是刑警寧澤褥琐,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站晤郑,受9級(jí)特大地震影響敌呈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜造寝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一驱富、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匹舞,春花似錦褐鸥、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至姊舵,卻和暖如春晰绎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背括丁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工荞下, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓尖昏,卻偏偏與公主長(zhǎng)得像仰税,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子抽诉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348

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

  • 1 場(chǎng)景問(wèn)題# 1.1 復(fù)雜的獎(jiǎng)金計(jì)算## 考慮這樣一個(gè)實(shí)際應(yīng)用:就是如何實(shí)現(xiàn)靈活的獎(jiǎng)金計(jì)算陨簇。 獎(jiǎng)金計(jì)算是相對(duì)復(fù)雜...
    七寸知架構(gòu)閱讀 3,974評(píng)論 4 67
  • 星期五早晨,我和同學(xué)們一起去天才夢(mèng)工廠玩迹淌。我去了在天才夢(mèng)工廠里的氣球館河绽、剪紙、魔法屋和披薩制作館 其中我最喜...
    琳2閱讀 406評(píng)論 1 1
  • 親朋乘舟平湖唉窃, 峰高蔽日疑暮耙饰。 山花散如雪, 恐入桃源深處纹份。 環(huán)顧苟跪, 環(huán)顧, 漁人入口山腰處矮嫉。
    黔來(lái)客閱讀 289評(píng)論 1 5
  • 多日已后,回顧前三周自己的生活牍疏,平靜蠢笋、瑣碎、但又有些事情值得回味鳞陨。 周三下了場(chǎng)雨昨寞,在漫長(zhǎng)炎炎夏日的雨后,頓時(shí)...
    無(wú)盡蒼穹閱讀 192評(píng)論 3 1
  • 跌倒了厦滤,不要哭援岩, 因?yàn)闇I水會(huì)模糊你眼前的路
    攸寧er閱讀 177評(píng)論 0 3