[Design pattern] factory method

Factory method

簡單來說是一套用來解決不用特別指定是哪個class,就可以建立物件的方法。

也就是把多個物件,多個方法,在外面變成了一個通用類別跟模組化,物件跟方法都為同一個通用的類別。

手法都是利用抽象化跟繼承跟protocol的方式來實現。

好處就是若要新增物件跟方法就直接去擴充模組,不比修改外面現有的邏輯。

 

Abstract factory method

他又是把物件跟方法分別抽象化了,不同類別,但還是互相有關聯(因protocol),各分為兩個通用的類別。

提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。

 

簡單的 factory method

也是一個通用的物件,input會有很多種可能,輸入到物件裡面,物件裡面會有swich case判斷,吐回去屬於某個物件的實體,那這個實體又follow通用抽象的protocol,去實作他,然後一樣又包了一層,用通用的物件去操作它,去耦合。

 

所以factory method好處:

1.通用(封裝)接口,只對單一個接口操作,若直接對物件操作會呼叫到一堆物件的class,這樣也比較簡單化。

2.大量運用到抽象(protocol or 抽象的繼承) > 去耦合化,物件跟物件可以切得比較乾淨。

3.模組化的擴充,物件的擴充,接口不變,只擴充物件。

4.一致性,透過工廠方法,都會遵循某些協定,使不同的物件有一致的行為模式。

繼續閱讀 “[Design pattern] factory method"

dealloc

dealloc

 

呼叫時機:

至於dealloc什麼時候會被call到?當這個物件class的計數變為0時,系統就會呼叫物件的dealloc去釋放(下中斷點看,或是印出來),通常class的畫面全部消失,這地方會被call到。

 

Case1:

若是畫面需求,一直共用某個class,物件就會一直被拉住,不會去釋放物件,在block裡面可以不用寫weak,如:

    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:ESCHeartCalculateMGRHeartDidUpdateNotification object:nil] subscribeNext:^(NSNotification *_Nullable n) {

        [self.titleBarView updateStarCount];

    }];

因為在block寫weak的原因,是要讓這個物件可以被釋放掉,不被retain住,那既然不用被釋放,那就不用寫了,但真的每個畫面都會用到嗎?疑問

Your own object which need to save, compare, copy

 

If you like to save non-foundation type obj (or you created OBJ) in memory , you need to followNSSecureCoding protocol and override as below method:

NSSecureCoding

+ (BOOL)supportsSecureCoding {

    return YES;

}
- (void)encodeWithCoder:(nonnull NSCoder *)aCoder {

    [aCoder encodeObject:self.forumID forKey:NSStringFromSelector(@selector(forumID))];

}
- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder {

    if (self = [super init]) {

        _forumID = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(forumID))];

    }

    return self;

}

 

Same , if you like to compare “equal" in your own object , you need to override NSObject inner method as below

- (NSUInteger)hash {     
NSUInteger value = 0;     
value ^= [self.userID hash];     
value ^= [self.displayName hash];     
value ^= self.isSubscriber;     
value ^= [self.avatarURL hash];     
return value; } 

- (BOOL)isEqual:(id)object {     
if (self == object) return YES;     
if (![object isMemberOfClass:self.class]) return NO;    
ReduxUserModel *other = (ReduxUserModel *)object;
if ([self hash] != [other hash]) return NO;     
if (![self.userID isEqualToNumber:other.userID]) return NO;     
if (![self.displayName isEqualToString:other.displayName]) return NO; 
if (self.isSubscriber != other.isSubscriber) return NO;     
if (self.avatarURL != other.avatarURL) {         
if (!self.avatarURL || !other.avatarURL || ![self.avatarURL isEqual:other.avatarURL]) return NO;     
}     
return YES; }

isEqual hash 解釋

nshipster的解釋

 

Same , if you like to copy value to your own object(you created), you need follow

NSCopying protocol and override as below method:

- (nonnull id)copyWithZone:(nullable NSZone *)zone {

    ReduxCommentModel *model = [[[self class] alloc] init];

    model.forumID = [self.forumID copy];
    model.displayName = [self.displayName copy];
    model.isSubscriber = self.isSubscriber;
    model.avatarURL = [self.avatarURL copy];
    return model;

}

相依注入DI(Dependency Injection)

為了降低代碼本身的耦合,也為了讓代碼更好測試,這裡我們需要引入DI(Dependency Injection,依賴注入)解耦合。

1.把想測試的方法弄成protocol,之後就可mock這個protocol進而測試該方法。

2.初始化init時注入

3.用Property時注入,ex lazy init

4.方法參數時注入

其他相依注入方法請看 https://www.objccn.io/issue-15-3/

對於以上幾種公開注入點的注入方式,比如說初始化注入,屬性注入,以及方法參數注入等都會讓人有一種破壞程序封裝性的感覺。我們總有一種想要掩蓋依賴注入銜接點的想法,這是可以理解的,因為我們知道這些銜接點是專門為單元測試準備的,它們並不屬於API 業務範疇。所以可以將它們聲明在category 中,並且放到一個單獨的頭文件裡。

 

是不是覺得為了達到測試目標不得已公開了許多不應公開的內部實現?首先,需要判斷一下基於你的代碼中現行所公開的API 是否能夠支撐完成測試代碼編寫(快速且確切)。如果不可以,並且你需要去操作那些本來是隱式的依賴對象,這說明很可能有其他的類也需要操作它。所以應該大膽將其抽象,把它當作依賴對象使用並進行單獨測試。

 

什麼是依賴注入?這個詞聽起來很艱深,而它的概念也不如網路上的人說得那麼簡單。那些人說,依賴注入其實就是把某個東西所需的資訊從外部設定給它而已:

這是錯的。依賴注入所注入的是依賴,而不是值或物件。所以,單純把某個屬性從自己建立,改成交給別的物件去指派,並不能算是依賴注入。

ref:https://www.appcoda.com.tw/massive-view-controller/

 

Reactive_Cocoa

Reactive_Cocoa 簡稱:"RAC" a.k.a “functional reactive programming" a.k.a “FRP"

 

RAC是由RCSignal來表示的,信號是數據流,可以被綁定或傳遞,可以把信號想成水龍頭裡的玻璃球,裡面不是水而是直徑跟水管一樣大的玻璃球,依次排列於水管中(序列化),不會有並行,水龍頭一開始是關起來的,直到有訂閱者(subscriber),才會打開,玻璃球才會傳遞給訂閱者。水龍頭上可以加上過濾的濾嘴(filter),合者通過,不合者過濾掉。也可把球變成符合自己的需求(map),也可以把多個水龍頭合併成一個(combineLatest:reduce:多個判斷式的KVO,ex:如登入註冊欄位,各個欄位需要有值…等邏輯&&組合起來,再去激活某UI)。

 

函數式響應編程特點:方法中會有返回值(返回物件實體,用來註冊或接收訊號,使得發送接收都在同一個方法裡),參數會有block。

 

簡單來說,其實他是把iOS裡面的一些交互式的訊息傳遞,封裝成方法,client再整合在一個interface裡面,ex: 使用KVO時,常常廣播對象跟接收對象都會散落在不同的class裡面,造成常要用廣播的key去找對應的方法,但若用Reactive_Cocoa,他可以把發廣播跟收到的後要處理的方法整合在同一層,同一個方法,同一個類裡面,使代碼變得更高聚合,方便管理,因為都寫在同一層所以不會有像block先設定後拿值先後順序的問題。

應用層面相當廣,監聽,KVO,delegate,網路getPost,targetAction…

繼續閱讀 “Reactive_Cocoa"

[Design pattern] MVVM

MVVM(Model,View,ViewModel)

MVC的mediator是controller.

MVVM的mediator是viewModel.

view:view/viewController >> own viewModel >> own model.

ex: 在tableView裡面cellForRowAt 直接塞viewModel給model,變得vc直接跟物件溝通(viewModel),而不是直接跟model溝通。

所以資料傳回來則為反方向model > viewModel > view 單一方向性。

Model不再與view耦合。(not like MVC, model coupling with view)

所以重點viewModel裡面到底放什麼?

1.放呈現view的邏輯跟狀態.

2.Raw data一開始都不太能用,所以也可放raw data轉成可用的資料邏輯。

繼續閱讀 “[Design pattern] MVVM"

[Swift]存取權限

swift

fileprivate > 只限這個swift的檔案裡面存取,其他”檔案“無法存取,無法跨檔案。

private > 只限這個swift 檔案裡面所定義的 class存取。

class xxx{
private let xxx : String
(只限在這裡面的class存取)
}

以下寫得較詳細

  • private: Visible just within the class.
  • private(set):Visible just set within the class.

  • fileprivate: Visible from anywhere in the same file.
  • internal: Visible from anywhere in the same module or app.
  • public: Visible anywhere outside the module.

There are additional access control related keywords:

  • open: Not only can it be used anywhere outside the module but also can be subclassed or overridden from outside.
  • final: Cannot be overridden or subclassed.

ref:

http://clavis.me/iOS/Access-Control-of-Swift4/

前往 Medium.com 檢視