大話設計模式

BetterDays發表於2018-07-10

設計模式這個東西,感覺就跟太極一樣,不是固定招式,需要學會然後忘記然後融會貫通。我看《大話設計模式》一書,前前後後大概看了一個月,看完一個自己用OC實現一個,到今天終於看完了。程式碼我已經上傳到了GitHub,大家有興趣的話可以下載看一眼,下面是程式碼目錄

大話設計模式

入口是ViewController,層級自我感覺良好。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//    [self factoryPattern];//工廠模式
//    [self strategyPattern];//策略模式 + 工廠模式
//    [self DecorativePattern];//裝飾模式
//    [self proxyPattern];//代理模式
//    [self factoryMethodPattern];//工廠方法模式
//    [self prototypePattern];//原型模式
//    [self templateMethodPattern];//模板方法模式
//    [self appearancePattern];//外觀模式
//    [self builderPattern];//建造者模式
//    [self oberverPattern];//觀察者模式
//    [self abstraceFactoryPattern];//抽象工廠模式
//    [self statePattern];//狀態模式
//    [self adapterPattern];//介面卡模式
//    [self mementoPattern];//備忘錄模式
//    [self combinatorialPattern];//組合模式
//    [self iteratorPattern];//迭代器模式
//    [self sigletonPattern];//單例模式
//    [self bridgePattern];//橋接模式
//    [self commandPattern];//命令模式
//    [self chainOfResponsibilityPattern];//職責鏈模式
//    [self mediatorPattern];//中介者模式
//    [self flyweightPattern];//享元模式
//    [self interpreterPattern];//直譯器模式
//    [self visitorPattern];//訪問者模式
}
複製程式碼

這裡把各個模式的簡單介紹貼一下,具體內容請到GitHub自行下載。

#pragma mark - 訪問者模式
/**
 *  訪問者模式:表示一個作用於某物件結構中的各元素的操作。它使你可以在不改變各元素的類的前提下
 *  定義作用於這些元素的新操作。
 *
 *  書中的例子是輸出了一段話,男人成功XXX,女人成功XXX,男人失敗XXX,女人失敗XXX,男人戀愛XXX,
 *  女人戀愛XXX。 這個例子能用訪問者模式的前提是人 只有男人跟女人兩個類,用了訪問者模式之後,如果
 *  要加一個狀態男人吃飯XXX,女人吃飯XXX,那麼只需要增加一個吃飯的狀態就可以了。否則的話需要在男人
 *  類裡增加一個吃飯狀態,在女人類裡增加一個吃飯狀態。
 *
 *  此類比較複雜,我在實現的時候也是參照了UML圖。
 */
- (void)visitorPattern{
    TFQObjectManager *manager = [[TFQObjectManager alloc] init];
    TFQMan *man = [[TFQMan alloc] initWithName:@"男人"];
    TFQWoman *woman = [[TFQWoman alloc] initWithName:@"女人"];
    [manager addPerson:man];
    [manager addPerson:woman];
    
    TFQPersonStateSuccess *success = [[TFQPersonStateSuccess alloc] init];
    success.name = @"成功";
    TFQPersonStateFail *fail = [[TFQPersonStateFail alloc] init];
    fail.name = @"失敗";
 
    [manager display:success];
    [manager display:fail];
}

#pragma mark - 直譯器模式
/**
 *  直譯器模式:給定一個語言,定義它的文法中的一中表示,並定義一個直譯器,這個直譯器使用該
 *  表示來解釋語言中的句子。
 *
 *  書中舉的例子晦澀難懂,我對樂譜這種東西有一種先天的抗拒,那就只好自己寫一個通俗易懂的例子
 *  來解釋一下這個直譯器模式。但是我從心底裡感覺這個直譯器模式就是對一種或者一系列行文封裝成
 *  一個方法,然後呼叫這個方法來達到目的。類似於工作流一樣的東西通過一個非常簡便的操作來實現
 *  一些經常發生的操作。 就像樂譜一樣,你通過輸入 “1234” 就可以播放dao ruai mi fa,這就是直譯器
 *  模式
 */
- (void)interpreterPattern{
    TFQMusicManager *musicManager = [[TFQMusicManager alloc] init];
    NSString *str = @"12343215";
    [musicManager accept:str];
}

#pragma mark - 享元模式
/**
 *  享元模式:運用共享技術有效地支援大量細粒度的物件。
 *
 *  書中舉的例子是小菜做網站,做完之後又需要做一個大體類似的網站,直接複製過去也能實現
 *  功能,但是浪費記憶體浪費時間,這時候就用到了共享模式,把相同的物件用同一個key,存放到字典中。
 *  這樣基本上不用建立新物件就可以實現功能。程式碼中解釋的很詳細了。可以研讀程式碼。
 */
- (void)flyweightPattern{
    TFQWebFactory *webFactory = [[TFQWebFactory alloc] init];
    TFQWebSite *site1 = [webFactory getWebSiteWithType:@"公司簡介"];
    site1.user = [[TFQWebUser alloc] initWithName:@"張三"];
    TFQWebSite *site2 = [webFactory getWebSiteWithType:@"部落格"];
    site2.user = [[TFQWebUser alloc] initWithName:@"張si"];
    TFQWebSite *site3 = [webFactory getWebSiteWithType:@"公司簡介"];
    site3.user = [[TFQWebUser alloc] initWithName:@"張五"];
    TFQWebSite *site4 = [webFactory getWebSiteWithType:@"公司簡介"];
    site4.user = [[TFQWebUser alloc] initWithName:@"張六"];
    
    [webFactory outputWebsites];
}

#pragma mark - 中介者模式
/**
 *  中介者模式:用一箇中介者物件來封裝一系列的物件互動。中介者使各物件不需要顯式地相互
 *  引用,從而使其耦合鬆散,而且可以獨立地改變他們之間的互動。
 *
 *  書中的例子是舉得聯合國的例子,各國之間交流都要通過聯合國。讓聯合國持有各個國家的屬性,
 *  國家的任何交流都要通過聯合國轉達。
 */
- (void)mediatorPattern{
    TFQUnitedNations *UN = [[TFQUnitedNations alloc] init];
    TFQUSA *USA = [[TFQUSA alloc] initWithMediator:UN];
    USA.name = @"美國";
    TFQIraq *Iraq = [[TFQIraq alloc] initWithMediator:UN];
    Iraq.name = @"伊拉克";
    UN.USA = USA;
    UN.Iraq = Iraq;
 
    [USA sendMessage:@"我要打你"];
    [Iraq sendMessage:@"我不要你打"];
}

#pragma mark - 職責鏈模式
/**
 *  職責鏈模式:使多個物件都有機會處理請求,從而避免請求的傳送者和接受者之間的耦合關係。
 *  將這個物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它位置。
 *
 *  書中舉得例子是小菜請求加薪,然後需要經理、總監、總經理依次審批。開始的程式碼是if判斷,
 *  雖然也能完成任務,但是略顯笨拙,改用職責鏈模式之後就洋氣了許多。
 *  個人感覺職責鏈模式跟狀態模式是一樣的,都是分情況,但是區別是啥呢,職責鏈的層級比較明顯,
 *  職責是一步一步變大的,側重性比較強。
 */
- (void)chainOfResponsibilityPattern{
    TFQRequest *request = [[TFQRequest alloc] init];
    request.requestName = @"張三";
//    request.requestType = @"加薪";
//    request.requestCount = 20000;
        request.requestType = @"請假";
        request.requestCount = 100;
    TFQLeader1 *leader1 = [[TFQLeader1 alloc] initWithName:@"小領導"];
    TFQLeader2 *leader2 = [[TFQLeader2 alloc] initWithName:@"中領導"];
    TFQLeader3 *leader3 = [[TFQLeader3 alloc] initWithName:@"大領導"];
    leader1.superior = leader2;
    leader2.superior = leader3;
    
    [leader1 handelRequest:request];
}

#pragma mark - 命令模式
/**
 *  命令模式:將一個請求封裝為一個物件,從而使你可用不同的請求對客戶進行引數化;
 *  對請求排隊或記錄請求日誌,以及支援可撤銷的操作。
 *
 *  書中的例子講的是小菜大鳥去吃烤串,然後用程式碼實現點烤串的操作,這時候就需要用低耦合的方式實現。
 */
- (void)commandPattern{
    TFQWaiter *waiter = [[TFQWaiter alloc] init];
    TFQCook *cook = [[TFQCook alloc] init];
    TFQChickenWing *wing = [[TFQChickenWing alloc] initWithCooke:cook];
    TFQSkewer *skewer = [[TFQSkewer alloc] initWithCooke:cook];
    
    [waiter receiveCommand:wing];
    [waiter receiveCommand:skewer];
    [waiter receiveCommand:wing];
    [waiter notifyCook];
}

#pragma mark - 橋接模式
/**
 *  橋接模式:講抽象部分與他的實現部分分離,使他們都可以獨立地變化。
 *
 *  橋接模式書中舉得例子是MN兩個品牌的手機,安裝兩個不同的遊戲,開始寫的話可能就需要寫
 *  M裡邊有兩個遊戲屬性,N裡邊有兩個遊戲屬性,這樣再有十個手機品牌的話,每個手機品牌就要
 *  寫兩個手機屬性。算下來就是寫了二十個手機屬性,
 *  現在呢,我們把手機單獨分離出來,把遊戲也分離出來,給手機新增一個載入遊戲的方法,醬紫
 *  的話遊戲就需要宣告一遍就可以了。
 */
- (void)bridgePattern{
    TFQPhoneM *M = [[TFQPhoneM alloc] init];
    TFQPhoneN *N = [[TFQPhoneN alloc] init];
    TFQPhoneGameA *gameA = [[TFQPhoneGameA alloc] init];
    TFQPhoneGameB *gameB = [[TFQPhoneGameB alloc] init];
    [M setPhoneGame:gameA];
    [M run];
    [M setPhoneGame:gameB];
    [M run];
    [N setPhoneGame:gameA];
    [N run];
}

#pragma mark - 單例模式
/**
 *  單例模式:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點
 *
 *  單例模式這種吊炸天的東西,大家應該都有使用,最簡單的方法就是dispatch_once建立,
 *  但是這種方法建立必須呼叫對應的類方法,如果用alloc 或者copy建立的話,還是會建立
 *  一個新物件,這時候大家就要重寫copywithzone方法,這個大家自行百度吧。
 *  但是自己用的話,來一個類方法就已經夠用了。自己雪薇注意一下就可以了。
 *  涉及到java的懶漢式單例,餓漢式單例。
 */
- (void)sigletonPattern{
    //大家可以列印一下試試  我記得onceToken初始化是0  執行之後變為1就再也不執行了。
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //do something create once
    });
}

#pragma mark - 迭代器模式
/**
 *  迭代器模式:提供一種方法順序訪問一個聚合物件中各個元素,而又不暴露該物件的內部表示
 *
 *  書中舉得例子是while迴圈,知道迴圈結束,while停止。
*   簡單來說就是for迴圈,把iOS的幾種迴圈列舉一下得了。具體的效率問題大家可以自己個兒百度去。
 */
- (void)iteratorPattern{
    for(int i=0; i<10; i++){
        NSLog(@"=%d",i);
    }
    NSArray *array = @[@1,@2,@3,@4];
    for(NSNumber *i in array){
        NSLog(@"==%@",i);
    }
    [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSLog(@"===%@",obj);
    }];
}


#pragma mark - 組合模式
/**
 *  組合模式:
 *
 *  組合模式簡直是一個吊炸天的設計模式,有那麼點遞迴的意思。
 *
 *  書中的例子是寫了一個大公司的OA系統,但是大公司下邊還有子公司,子公司還要子公司,這時候組合模式的
 *  好處就體現的淋漓盡致。
 *                                 -HR
 *                     -HR         -財務     -HR
 *  下邊程式碼的結構  -北京 -石家莊分公司 -橋西分公司-財務
 *                     -財務        -橋東分公司-HR
 *                                          -財務
 */
- (void)combinatorialPattern{
    TFQConcreteCompany *beijingCompany = [[TFQConcreteCompany alloc] initWithName:@"北京總公司"];
    TFQHRDepartment *beijingHR = [[TFQHRDepartment alloc] initWithName:@"北京HR"];
    TFQMoneyDepartment *beijingMoney = [[TFQMoneyDepartment alloc] initWithName:@"北京財務"];
    [beijingCompany add:beijingHR];
    [beijingCompany add:beijingMoney];
    
    TFQConcreteCompany *shijiazhuangCompany = [[TFQConcreteCompany alloc] initWithName:@"石家莊分公司"];
    [beijingCompany add:shijiazhuangCompany];
    TFQHRDepartment *shijiazhuangHR = [[TFQHRDepartment alloc] initWithName:@"石家莊HR"];
    TFQMoneyDepartment *shijiazhuangMoney = [[TFQMoneyDepartment alloc] initWithName:@"石家莊財務"];
    [shijiazhuangCompany add:shijiazhuangHR];
    [shijiazhuangCompany add:shijiazhuangMoney];
    
    TFQConcreteCompany *qiaodongCompany = [[TFQConcreteCompany alloc] initWithName:@"石家莊橋東分公司"];
    [shijiazhuangCompany add:qiaodongCompany];
    TFQHRDepartment *qiaodongHR = [[TFQHRDepartment alloc] initWithName:@"石家莊橋東HR"];
    TFQMoneyDepartment *qiaodongMoney = [[TFQMoneyDepartment alloc] initWithName:@"石家莊橋東財務"];
    [qiaodongCompany add:qiaodongHR];
    [qiaodongCompany add:qiaodongMoney];
    
    TFQConcreteCompany *qiaoxiCompany = [[TFQConcreteCompany alloc] initWithName:@"石家莊橋西分公司"];
    [shijiazhuangCompany add:qiaoxiCompany];
    TFQHRDepartment *qiaoxiHR = [[TFQHRDepartment alloc] initWithName:@"石家莊橋西HR"];
    TFQMoneyDepartment *qiaoxiMoney = [[TFQMoneyDepartment alloc] initWithName:@"石家莊橋西財務"];
    [qiaoxiCompany add:qiaoxiHR];
    [qiaoxiCompany add:qiaoxiMoney];
    
    //列印結構圖
    [beijingCompany displayCompanyWithCount:1];
}

#pragma mark - 備忘錄模式
/**
 *  備忘錄模式:在不破壞封裝性的前提下,捕獲一個物件的內部狀態,並在該物件之外儲存這個狀態。
 *  這樣以後就可將該物件恢復到原先儲存的狀態。
 *
 *  我只能說,雞肋,哈哈哈,就是用第三方類儲存了對應的屬性而已。
 *  寫個例子,打遊戲儲存血量跟藍量
 *  其實這些個涉及模式中,每個設計模式都有管理者類,寫法更加嚴謹,但是我就是不想寫管理者類。
 */
- (void)mementoPattern{
    TFQGamePlayer *player = [[TFQGamePlayer alloc] init];
    player.blood = @"100";
    player.chaKeLa = @"100";
    TFQRecord *record = [[TFQRecord alloc] init];
    [record saveWithPlayer:player];
    NSLog(@"打仗前血量:%@ 查克拉:%@",player.blood,player.chaKeLa);
    player.blood = @"90";
    player.chaKeLa = @"90";
    NSLog(@"打仗後血量:%@ 查克拉:%@",player.blood,player.chaKeLa);
    [record resurrectionWithPlayer:player];
    NSLog(@"恢復進度後血量:%@ 查克拉:%@",player.blood,player.chaKeLa);
}

#pragma mark - 介面卡模式
/**
 *  介面卡模式:將一個類的介面轉換成客戶希望的另外一個介面。介面卡模式使得原本由於介面不相容
 *  而不能一起工作的那些類可以一起工作。
 *
 *  其實大家實際開發中肯定都用過介面卡模式,我也用過,原來的老程式碼有一部分不敢動,但是又有新需求,
 *  只好小小的適配一下,但是那時候用的時候,並不知道這是一個設計模式。
 *
 *  書中的例子說的是姚明剛去NBA工作,不懂英語,無法合理的理解戰術,這時候就需要一個翻譯來告訴
 *  姚明需要做些什麼,介面卡的很好提現,通俗易懂。
 */
- (void)adapterPattern{
    TFQNBAPlayer *kobe = [[TFQNBAKobe alloc] initWithName:@"kobe"];
    [kobe attack];
    TFQNBAPlayer *translater = [[TFQTranslater alloc] initWithName:@"yaoming"];
    [translater defense];
}

#pragma mark - 狀態模式
/**
 *  狀態模式:當一個物件的內在狀態改變時允許改變其行為,這個物件看起來像是改變了其類。
 *
 *  書中的例子是小菜加班,上午精神飽滿,中午吃飯午休,下午困,幹完活就可以正點下班,
 *  幹不完活兒,就只能繼續加班。這一天的各種狀態是以時間判斷的,這裡邊至少要寫5、6個if else
 *  語句,以後再做修改就會相當費勁,所以引入了狀態模式。
 *
 *  狀態模式的巨大優點就是隔離了變化,改了那個狀態一目瞭然別的狀態不用管,但是狀態模式優點繞。需要
 *  手動實現以下,哪怕是實現一個demo也好
 */
- (void)statePattern{
    TFQWork *work = [[TFQWork alloc] init];
    work.hour = 9;
    [work writeCode];
    work.hour= 13;
    [work writeCode];
    work.hour = 23;
    [work writeCode];
}

#pragma mark - 抽象工廠模式
/**
 *  抽象工廠模式:提供一個建立一系列相關或相互依賴物件的介面,而無需指定它們具體的類。
 *  java裡邊的介面,iOS這裡全部用繼承來實現。
 *
 *  先來一波抽象工廠的文字解釋,書中的例子就是資料庫從sqlserver 切換到了 access資料庫,導致大部分程式碼需要重寫。
 *  那是怎麼解決這個問題的呢?
 *  從源頭上就開始寫抽象工廠,然後例項化sqlserver、access兩個子類,這樣子前期工作量大一點,但是後期切換起來方便。
 *  但是這個東西,我只能大體的跟大家演練一下,說到底我感覺這也是個雞肋的設計模式。
 *
 *  java裡邊用到了反射,iOS裡邊怎麼解決這個棘手的問題呢。雪薇有點尷尬。 難道要用NSClassFromString?
 */
- (void)abstraceFactoryPattern{
    //如果想用資料庫,只需要修改這裡的屬性值就可以了
    TFQDataBaseManager.databaseName = @"sqlserver";
    //TFQDataBaseManager.databaseName = @"oracle";
    TFQDataBase *database = [TFQDataBaseManager getDataBase];
    [database connectDB];
    TFQCRUD *crud = [TFQDataBaseManager getCRUD];
    [crud crud];
}

#pragma mark - 觀察者模式
/**
 *  建造者模式:定義了一種一對多的依賴關係,讓多個觀察者物件同時監聽某一個主題物件。這個主題物件在狀態發生變化時,
 *  會通知所有的觀察者物件,使他們能夠自動更新自己。
 *
 *  java 中有一個委託事件 public event EventHandler update; ios 裡邊沒有,這裡用通知實現。
 *  但是用通知實現起來沒什麼意思,天天寫通知,都快寫爛了,但是那又有什麼辦法呢。
 *  iOS用通知強硬的實現觀察者模式,哈哈哈,其實更形象的觀察者模式是kvo,大家可以研究一下,其實精髓就是建造子類重寫了set方法。
 */
- (void)oberverPattern{
    TFQNotification *notification = [[TFQNotification alloc] init];
    TFQObserver1 *observer1 = [[TFQObserver1 alloc] init];
    TFQObserver2 *observer2 = [[TFQObserver2 alloc] init];
    //監聽通知
    [[NSNotificationCenter defaultCenter] addObserver:observer1 selector:@selector(receiveNotifacation) name:@"1" object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:observer2 selector:@selector(receive) name:@"2" object:nil];
    
    //建立通知
    NSNotification *no1 = [[NSNotification alloc] initWithName:@"1" object:nil userInfo:nil];
    NSNotification *no2 = [[NSNotification alloc] initWithName:@"2" object:nil userInfo:nil];
    [notification.notifications addObject:no1];
    [notification.notifications addObject:no2];
    
    //傳送通知
    [notification sendNotification];
    
    //移除通知
    [[NSNotificationCenter defaultCenter] removeObserver:observer1];
    [[NSNotificationCenter defaultCenter] removeObserver:observer2];
}

#pragma mark - 建造者模式
/**
 *  建造者模式:將一個複雜的物件的構建與他的表示分離,使得同樣的構建過程可以建立不同的表示。
 *
 *  書中的例子是用程式碼畫小人兒,畫完胖的畫瘦的,但是有時候可能會忘記畫一條腿,為了避免這種錯誤就出現了建造者模式
 *  建造者模式在java裡邊其實就是建立了一個抽象類,讓子類繼承他必須實現某些方法。這樣就不會少呼叫東西。
 *  但是iOS裡邊沒有抽象類怎麼實現呢?那就只能在父類方法實現體裡邊寫輸出語句或者alert語句,醬紫少實現方法就會提示你,
 *  但是這個方法只能再執行的時候提示你,沒辦法,誰讓iOS沒有抽象類的概念呢。
 *  裡邊有一個指揮者類,用它來控制建造過程,也用他來隔離使用者與建造過程的關聯,個人感覺沒什麼卵用
 *  其實父類裡邊的這個build方法就是相當於這個指揮者類的功能,本人感覺再寫個指揮者類會程式碼冗餘,就直接寫到父類裡了
 *
 *  下邊開始畫小人兒
 */
- (void)builderPattern{
    TFQBuilderA *buildA = [[TFQBuilderA alloc] init];
    [buildA beginBuild];
    
    TFQBuilderB *buildB = [[TFQBuilderB alloc] init];
    [buildB beginBuild];
}

#pragma mark - 外觀模式
/**
 *  外觀模式:為子系統中的一組介面提供一個一致的介面,此模式定義了一個高層介面,這個介面使得這一子系統更加容易使用。
 *
 *  個人理解:外觀模式就是迪米特法則的正式運用。讓一個第三方的類去給你管理其他的類,你不需要知道其他類的具體實現。
 *  書中的例子是,新股民需要買多支股票,就需要了解多支股票的資訊,但是如果新股民找一個管理人的話,那麼新股民就
 *  不需要了解股票的具體資訊,把錢直接給這個管理人,等著拿利息就行了。
 *
 */
- (void)appearancePattern{
    TFQFund *fund = [[TFQFund alloc] init];
    [fund buy];
    [fund sell];
}

#pragma mark - 迪米特法則
/**
 *  迪米特法則(也叫最少知識原則):如果兩個類不必彼此直接通訊,那麼這兩個類就不應當發生直接的相互作用。如果其中一個
 *  類需要呼叫另一個類的某一個方法的話,可以通過第三者轉發這個呼叫。   強調了類之間的鬆耦合。
 *
 *  拿書中的例子來說,小菜入職需要去運維部門配置電腦,但是不必要直接找到運維部門的小張去配置電腦,直接找到運維部門兒的
 *  領導說:我要配置電腦,這時候領導叫小張去給你配置電腦,如果小張有事兒,領導還可以指派小李給你配置電腦。耦合性降低。
 *
 *  類之間的耦合越弱,越有利於複用。
 */


#pragma mark - 模板方法模式
/**
 *  模板方法模式:定義一個操作中的演算法的骨架,而將一些步驟延遲到子類中,模板方法使得一些子類可以不改變
 *  一個演算法的結構即可衝定義該演算法的某些特定步驟
 *
 *  模板方法就是用簡單的繼承才做一些操作。
 *  書中的例子就是老師在黑板上出試卷,學生ABC需要把題目抄下來然後答題,如果學生ABC把題目都抄一遍的話題目可能會抄錯,
 *  而且浪費時間,所以就要用一個父類來存放試卷,這時候就要儘可能的減少相同程式碼的書寫,儘量寫一次。把不變的程式碼做好封裝。
 */
- (void)templateMethodPattern{
    TFQTestPaperA *testPaperA = [[TFQTestPaperA alloc] init];
    [testPaperA answerQuestion];
    TFQTestPaperB *testPaperB = [[TFQTestPaperB alloc] init];
    [testPaperB answerQuestion];
}

#pragma mark - 原型模式
/**
 *  原型模式:用原型例項指定建立物件的種類,並且通過拷貝政協原型建立新的物件。
 *  原型模式用到了java的重要知識拷貝物件,而且是深拷貝,Java中需要實現Cloneable介面,在clone方法中進行操作。但是不過OC更偏向於Java這種
 *  方式,OC中如果一個物件需要被拷貝,他需要實現協議:<NSCopying>、<NSMutableCopying>從名字上我們可以看到,一個協議是用於不可變物件的,
 *  一個協議適用於可變物件的
 */
- (void)prototypePattern{
    TFQCopyObject *copyObject = [[TFQCopyObject alloc] init];
    copyObject.name = @"1";
    copyObject.array = @[@1,@"2"];
    NSLog(@"%@,%@",copyObject.name,copyObject.array);
    TFQCopyObject *copyObject2 = [copyObject copy];
    copyObject2.name = @"老鐵";
    copyObject2.array = @[@4,@"hello world"];
    NSLog(@"%@,%@",copyObject2.name,copyObject2.array);
}


#pragma mark - 工廠方法模式
/**
 *  工廠方法模式:定義一個用於建立物件的介面,讓子類決定例項化哪一個類。工廠方法使一個類的例項化延遲到其子類。
 *  工廠方法的精髓是擴充套件性極強,而且不影響原來的邏輯。
 *  書中例子的雷鋒工廠是用介面實現的,但是OC裡邊沒有介面,只好用父類來曲線救國了
 *
 *  書中的例子是學雷鋒,現在有學雷鋒的學生、志願者,
 *  如果用簡單工廠模式:
 *     那就是建立以下類。需要幫助的老奶奶、學雷鋒父類、學雷鋒學生子類、學雷鋒志願者子類4個類。
 *  如果是工廠方法模式:
 *     需要建立老奶奶、學雷鋒父類、學雷鋒工廠、學雷鋒學生工廠、學雷鋒學生、學雷鋒志願者工廠、學雷鋒志願者6個類。
 *  下邊比上邊多了兩個工廠類,但是修改起來那簡直就是很舒服了,簡單易操作,易理解。只需要改一個地方。
 *
 */
- (void)factoryMethodPattern{
    //如果要換人的話那麼只需要改動這一個地方即可:TFQStudentFactory替換為TFQVolunteerFactory就變成了志願者學雷鋒了
    TFQLeiFengFactory *factory = [[TFQStudentFactory alloc] init];
    TFQLeiFeng *leiFeng = [factory createLeiFeng];
    [leiFeng sweep];
    [leiFeng wash];
}



#pragma mark - 代理模式
/**
 *  代理模式:為其他物件提供一種代理以控制對這個物件的訪問。
 *  A通過B達到與C溝通的目的,這就是代理模式。 AB需要實現同一個介面,看起來是B與C溝通,其實B的方法內部都是A的操作,簡介實現了
 *  A與C的溝通。
 *  這裡的代理其實理念上跟iOS的代理是一樣的,只不過iOS的代理是一個弱引用delegate,沒有B這個第三方。
 *
 *  既然OC裡邊沒有介面這個概念,那麼只好用繼承來實現了
 *  例子還用書中的例子,A通過B追求C,追求方式是送禮物
 *
 */
- (void)proxyPattern{
    TFQGirlC *girl = [[TFQGirlC alloc] initWithName:@"小芳"];
    TFQGiftB *giftB = [[TFQGiftB alloc] initWithGirl:girl];
    [giftB sendFlower];
    [giftB sendChocolate];
}

#pragma mark - 裝飾模式
/**
 *  裝飾模式:動態地給一個物件新增一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。
 *  裝飾模式用到了一個java的重要知識,構造方法:與類同名沒有返回值。
 *
 *  大話涉及模式中舉的例子是穿衣服的問題,利用構造方法做一些手腳,把A的子類B的屬性賦值到A的子類C中,實現了屬性傳遞。
 *  那我們OC裡邊怎麼辦呢,用init 方法,替換了書中例子中的new操作 跟Decorate操作。
 *
 *  我們繼續搞穿衣服的例子   person:人類   decorator:服飾父類。 其餘的為服飾子類。
 *  寫完之後個人感覺裝飾模式作用不太大,可能應用場景比較苛刻。不過簡直寫完是真的很舒服,對繼承理解的更深刻了。
 *  show方法這裡可能比較繞,大家可以根據方法一行一行捋程式碼,捋完之後恍然大悟。也可以用笨辦法,把繼承的show方法全部在當前子類中重寫一遍。
 *  這樣看起來就比較好理解了。很舒服。
 */
- (void)DecorativePattern{
    TFQPerson *person = [[TFQPerson alloc] initWithName:@"張三"];
    TFQHat *hat = [[TFQHat alloc] initWithPerson:person];
    TFQShoes *shoes = [[TFQShoes alloc] initWithPerson:hat];
    [shoes show];
}

#pragma mark - 依賴倒轉原則
/**
 *  依賴倒轉原則:高層模組不應該依賴底層模組
 *
 */


#pragma mark - 開放-封閉原則
/**
 *  開放-封閉原則: 軟體實體(類、模組、函式等等)應該可以擴充套件,但是不可修改
 *  當前實體內部應該儘量少修改,但是改實體擴充套件性要好
 */

#pragma mark - 單一職責原則
/**
 *  單一職責原則: 就一個類而言,應該僅有一個引起它變化的原因
 *  這個解釋可以說是通俗易懂了:高內聚低耦合
 */

#pragma mark - StrategyPattern 策略模式
/**
 *  策略模式舉的例子是 商場打折、滿減、滿贈活動,其實在我看來就是一個封裝,取了一個裝逼的名字而已,
 *  然後這裡講解的例子是把策略模式跟工廠模式結合來實現計算器,其實就是找了一箇中間類,把“變化”封裝到這個中間類而已。
 */
- (void)strategyPattern{
    [TFQStraTegy getResultWithText:self.textField.text];
}

#pragma mark - FactoryPattern 簡單工廠模式
/**
 *  簡單工廠模式舉的例子是 計算器的實現,很好的詮釋了封裝、整合、多型的用法。
 */
- (void)factoryPattern{
    [self calculateResult];
}

- (void)calculateResult{
    NSString *str = self.textField.text;
    TFQOperation *operation;
    NSString *flag;
    if([str containsString:@"+"]){
        flag = @"+";
        operation = [[TFQAdd alloc] init];
    }else if([str containsString:@"-"]){
        flag = @"-";
        operation = [[TFQSubtract alloc] init];
    }else if([str containsString:@"*"]){
        flag = @"*";
        operation = [[TFQMultiply alloc] init];
    }else if([str containsString:@"/"]){
        flag = @"/";
        operation = [[TFQDivide alloc] init];
    }else{
        NSLog(@"輸入錯誤");
        return;
    }
    int location = (int)[str rangeOfString:flag].location;
    operation.numA = [[str substringToIndex:location] intValue];
    operation.numB = [[str substringFromIndex:location+1] intValue];
    float result = [operation getResult];
    NSLog(@"%d%@%d = %.2f",operation.numA,flag,operation.numB,result);
}
複製程式碼

相關文章