iOS 設(shè)計模式的應用 ② 工廠方法

前言

????幾乎在每個面向?qū)ο笳Z言寫的應用程序里都能看到工廠方法。對象工廠與生成有形產(chǎn)品的真實工廠類似,例如:制鞋廠生產(chǎn)鞋,手機工廠生產(chǎn)手機。比方說,你讓工廠給你生產(chǎn)些產(chǎn)品,發(fā)送一個 “生產(chǎn)產(chǎn)品” 的消息,工廠按照相同的 “生產(chǎn)產(chǎn)品的協(xié)議” ,啟動其生產(chǎn)線,過程結(jié)束后,每個廠家都返回所生產(chǎn)的特定類型的產(chǎn)品。我們把 ”生產(chǎn)“ 這個有魔力的詞稱作工廠方法,因為它是命令生產(chǎn)者得到想要的產(chǎn)品的方法。

什么是工廠方法模式

????工廠方法,也成為虛構(gòu)造器。定義一個創(chuàng)建對象的接口,讓其子類自己決定實例化哪一個工廠類,工廠方法模式使其創(chuàng)建過程延遲到子類進行。其從代碼中消除了對特有類的耦合,只需處理抽象接口,同一代碼得到復用。

工廠方法模式的類圖.png

????抽象的 Product 定義了工廠方法創(chuàng)建的對象的接口,ConcreteProduct 實現(xiàn)了 Product 的接口。Factory 定義了返回 Product 對象的工廠方法,ConcreteFactory 重載了工廠方法,返回 ConcreteProduct 實例。

什么時候使用工廠方法

  • 編譯時無法準確預期要創(chuàng)建的對象的類
  • 類想讓其子類決定在運行時創(chuàng)建什么
  • 類有若干輔助類為其子類,將返回哪個子類這一信息局部化。

工廠方法使用場景舉例

  1. 日志記錄器:記錄可能記錄到本地硬盤、系統(tǒng)事件、遠程服務器等,用戶可以選擇記錄日志到什么地方。
  2. 數(shù)據(jù)庫訪問:當不知道最后系統(tǒng)采用哪一類數(shù)據(jù)庫,以及數(shù)據(jù)庫可能有變化時。

工廠方法的優(yōu)缺點

優(yōu)點:

  1. 一個調(diào)用者想創(chuàng)建一個對象,只要知道其名稱就可以了。
  2. 擴展性高,如果想增加一個產(chǎn)品,只要擴展一個工廠類就可以,無需調(diào)用的代碼
  3. 屏蔽產(chǎn)品的具體實現(xiàn),調(diào)用者只關(guān)心產(chǎn)品的接口。

缺點

  1. 每次增加一個產(chǎn)品時,都需要增加一個具體類和對象實現(xiàn)工廠,使得系統(tǒng)中類的個數(shù)成倍增加,在一定程度上增加了系統(tǒng)的復雜度,同時也增加了系統(tǒng)具體類的依賴。

實現(xiàn)

普通工廠方法的實現(xiàn)

  1. 定義一個抽象 Shape 協(xié)議。

    @protocol Shape <NSObject>
    
    @property (nonatomic, copy) NSString *Id;
    
    @property (nonatomic, copy) NSString *type;
    
    - (void)draw;
    @end
    
  2. 定義三個 Shape 的子類分別為 Rectangle、CircleSquare

    @interface Rectangle : NSObject<Shape>
    @end
    @implementation Rectangle
    
    @synthesize Id;
    
    @synthesize type;
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.type =  @"Rectangle";
        }
        return self;
    }
    - (void)draw{
        NSLog(@"call Rectangle draw() method.");
    }
    
    @end
    
      
    @interface Circle : NSObject<Shape>
    @end
    @implementation Circle
    @synthesize Id;
    
    @synthesize type;
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.type =  @"Circle";
        }
        return self;
    }
    - (void)draw{
        NSLog(@"call Circle draw() method.");
    }
    @end
      
    @interface Square : NSObject<Shape>
    @end
    @implementation Square
    @synthesize Id;
    
    @synthesize type;
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            self.type =  @"Square";
        }
        return self;
    }
    - (void)draw{
        NSLog(@"call Square draw() method.");
    }
    @end
    
  1. 定義一個 ShapeFactory 抽象 @protocol,負責創(chuàng)建 Shape,以及遵守協(xié)調(diào)的 CircleFactory、RectangleFactorySquareFactory 負責創(chuàng)建 CircleRectangleSquare 。

    @protocol ShapeFactory 
    - (id<Shape>)shapeWithId:(NSString *)Id;
    @end
      
    @interface CircleFactory : NSObject <ShapeFactory>
    @end
    @implementation CircleFactory
    - (Circle *)shapeWithId:(NSString *)Id{
        Circle *circle = [Circle new];
        circle.Id = Id;
        return circle;
    }
    
    @end
      
    @interface RectangleFactory : NSObject <ShapeFactory>
    
    @end
    @implementation RectangleFactory
    - (id<Shape>)shapeWithId:(NSString *)Id{
        Rectangle *rectangle = [Rectangle new];
        rectangle.Id = Id;
        return rectangle;
    }
    @end
      
    @interface SquareFactory : NSObject <ShapeFactory>
    
    @end
    @implementation SquareFactory
    - (id<Shape>)shapeWithId:(NSString *)Id{
        Square *square = [Square new];
        square.Id = Id;
        return square;
    }
    
    
  2. 執(zhí)行方法為:- (id<Shape>)loadShapeWithFactory:(id<ShapeFactory>)factory

    - (id<Shape>)loadShapeWithId:(NSString *)Id Factory:(ShapeFactory *)factory{
      return [factory shapeWithId:Id];
    }
    
  1. 通過傳入不同的 Factory ,獲得不同類型的 Shape 。例如:

    [self loadShapeWithId:@"2" Factory:[CircleFactory new]];
    

簡單工廠方法

????在簡單工廠中,可以根據(jù)參數(shù)的不同返回不同類的實例。簡單工廠專門定義一個 Factory 類來負責創(chuàng)建其他類的實例,被創(chuàng)建的實例通常都具有共同的父類。例如,刪除上面的各個工廠,統(tǒng)一由 ShapeFactroy類根據(jù)遵守Shape 類型的類名反射創(chuàng)建子類的實例。

@interface ShapeFactory : NSObject

+ (id<Shape>)shapeWithId:(NSString *)Id Type:(NSString *)type;

@end
@implementation ShapeFactory
+ (id<Shape>)shapeWithId:(NSString *)Id Type:(NSString *)type{
    Class class =  NSClassFromString(type);
    if ([class conformsToProtocol:@protocol(Shape)]) {
        id <Shape>object = [class new];
        object.Id = Id;
        return object;
    }
    return  nil;
}
@end

可以將簡單工廠看為工廠方法模式的一個特例,將全部創(chuàng)建邏輯集中到了一個工廠類中;它所能創(chuàng)建的類只能是事先考慮到的,如果需要添加新的類,則就需要改變工廠類了。

總結(jié)

????工廠方法是面向?qū)ο筌浖O(shè)計中應用非常普遍的設(shè)計模式。工廠方法從代碼中消除了對應用程序特有類的耦合。代碼只需要處理 <Product> 抽象接口,所以同一代碼得到復用,在應用程序中與用戶定義的任何 ConcreteProduct 實體類一起工作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容