美文网首页
iOS 设计模式(四)-工厂模式

iOS 设计模式(四)-工厂模式

作者: 搬砖的crystal | 来源:发表于2021-12-31 17:00 被阅读0次

    一、简单工厂模式

    简单工厂的生活场景,卖早点的小摊贩,他给你提供包子,馒头,地沟油烙的煎饼等,小贩是一个工厂,它生产包子,馒头,地沟油烙的煎饼。

    1.简单工厂模式的参与者
    • 工厂(Factory)角色:接受客户端的请求,通过请求负责创建相应的产品对象。
    • 抽象产品(Abstract Product)角色:是工厂模式所创建对象的父类或是共同拥有的接口。可是抽象类或接口。
    • 具体产品(ConcreteProduct)对象:工厂模式所创建的对象都是这个角色的实例。
    2.简单工厂模式的演变

    当系统中只有唯一的产品时,可以省略抽象产品,如图1所示。这样,工厂角色与具体产品可以合并。

    3.简单工厂模式的优缺点

    工厂类含有必要的创建何种产品的逻辑,这样客户端只需要请求需要的产品,而不需要理会产品的实现细节。
    工厂类只有一个,它集中了所有产品创建的逻辑,它将是整个系统的瓶颈,同时造成系统难以拓展。
    简单工厂模式通常使用静态工厂方法,这使得工厂类无法由子类继承,这使得工厂角色无法形成基于继承的等级结构。

    4.示例

    工厂的角色

    //作为工厂的角色
    #import "SFOperation.h"
    #import <Foundation/Foundation.h>
    typedef NS_ENUM(NSInteger, SFFactoryProductType){
        SFFactoryProductTypeMantou,
        SFFactoryProductTypeYoutiao,
    };
    @interface SFFactory : NSObject
    //工厂(Factory)角色:接受客户端的请求,通过请求负责创建相应的产品对象。
    + (SFOperation *)operationBreakfast:(SFFactoryProductType )breakfastType;
    @end
    
    #import "SFFactory.h"
    #import "SFOperationMantou.h"
    #import "SFOperationYoutiao.h"
    @implementation SFFactory
    + (SFOperation *)operationBreakfast:(SFFactoryProductType)breakfastType{
        //通过枚举返回不同的产品
        SFOperation *operation;
        switch (breakfastType) {
            case SFFactoryProductTypeMantou:
                operation = [[SFOperationMantou alloc] init];
                break;
            case SFFactoryProductTypeYoutiao:
                operation = [[SFOperationYoutiao alloc] init];
                break;
            default:
                return nil;
                break;
        }
        return operation;
    }
    @end
    

    抽象产品角色

    //抽象产品角色,通过子类化它来获得具体的角色
    #import <Foundation/Foundation.h>
    @interface SFOperation : NSObject
    - (void)productBreakfast;
    @end
    
    #import "SFOperation.h"
    
    @implementation SFOperation
    - (void)productBreakfast{
    }
    @end
    

    具体产品

    #import <Foundation/Foundation.h>
    #import "SFOperation.h"
    //具体产品角色,SFOperation的子类化
    @interface SFOperationMantou : SFOperation
    @end
    
    #import "SFOperationMantou.h"
    @implementation SFOperationMantou
    - (void)productBreakfast{
        NSLog(@"生产馒头");
    }
    @end
    
    #import <Foundation/Foundation.h>
    #import "SFOperation.h"
    
    @interface SFOperationYoutiao : SFOperation
    @end
    
    #import "SFOperationYoutiao.h"
    @implementation SFOperationYoutiao
    - (void)productBreakfast{
        NSLog(@"生产油条");
    }
    @end
    

    调用

        SFOperation *sfOperation = [SFFactory operationBreakfast:SFFactoryProductTypeYoutiao];
        [sfOperation productBreakfast];
    

    SFFactory作为一个工厂,里面包含了创建产品的逻辑,这里使用一个枚举来控制是创建油条还是馒头的具体产品。但是这里的问题就是,如果产品类的逻辑非常复杂,那么这个共产类会复杂的不可控。当然,外部调用的话,根本无需关心内部如何创建具体的产品,因为抽象产品类SFOperation已经制定了一套接口规范。

    二、工厂模式

    工厂方法使用OOP的多态性,将工厂和产品都抽象出一个基类,在基类中定义统一的接口,然后在具体的工厂中创建具体的产品。

    1.工厂方法模式中的参与者
    • 抽象工厂角色:与应用程序无关,任何在模式中创建对象的工厂必须实现这个接口。
    • 具体工厂角色:实现了抽象工厂接口的具体类,含有与引用密切相关的逻辑,并且受到应用程序的调用以创建产品对象。
    • 抽象产品角色:工厂方法所创建产品对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
    • 具体产品角色:这个角色实现了抽象产品角色所声名的接口。工厂方法所创建的每个具体产品对象都是某个具体产品角色的实例。
    2.工厂方法的优缺点

    降低了工厂类的内聚,满足了类之间的层次关系,又很好的符合了面向对象设计中的单一职责原则,这样有利于程序的拓展。

    3.示例

    抽象工厂角色

    #import <Foundation/Foundation.h>
    @class FFOperation;
    @interface FFactory : NSObject
    + (FFOperation *)createOperation;
    @end
    
    #import "FFactory.h"
    #import "FFOperation.h"
    @implementation FFactory
    + (FFOperation *)createOperation{
        FFOperation *operation = [[FFOperation alloc] init];
        return operation;
    }
    @end
    

    具体工厂角色

    #import <UIKit/UIKit.h>
    #import "FFactory.h"
    @interface FFactoryMantou : FFactory
    
    @end
    
    #import "FFactoryMantou.h"
    #import "FFOperationMantou.h"
    @implementation FFactoryMantou
    + (FFOperation *)createOperation{
        return [[FFOperationMantou alloc] init];
    }
    @end
    

    抽象产品角色

    #import <Foundation/Foundation.h>
    
    @interface FFOperation : NSObject
    - (void)productBreakfast;
    @end
    
    #import "FFOperation.h"
    
    @implementation FFOperation
    - (void)productBreakfast{
        
    }
    @end
    

    具体产品角色

    #import "FFOperation.h"
    
    @interface FFOperationMantou : FFOperation
    
    @end
    
    #import "FFOperationMantou.h"
    
    @implementation FFOperationMantou
    - (void)productBreakfast{
        NSLog(@"馒头");
    }
    @end
    

    调用

        FFOperation *ffOperation = [FFactoryMantou createOperation];
        [ffOperation productBreakfast];
    

    与简单工厂模式把所有产品都放到SFFactory来获取相比,工厂模式每次需要一个新的产品,就需要新建一个具体工厂来生成新的产品。当你需要豆浆的时候,只要新建一个继承与FFactory的工厂类,再创建一个继承于FFOperation的具体产品就可以创建新的产品了。对原来的代码都不需要做任何修改。这就使得产品的拓展变得简单。

    三、抽象工厂模式

    所谓抽象工厂是指一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象。

    1.抽象工厂中的参与者
    • 抽象工厂(Abstract Factory)角色: 担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。
    • 具体工厂(Concrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
    • 抽象产品(Abstract Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
    • 具体产品(Concrete Product)角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。
    2.抽象工厂的使用场景
    • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
    • 这个系统有多于一个的产品族,而系统只消费其中某一产品族。
      同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
    • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
    3.抽象工厂模式与工厂方法模式的区别

    (1)工厂方法模式:每个抽象产品派生多个具体产品类,每个抽象工厂类派生多个具体工厂类,每个具体工厂类负责一个具体产品的实例创建;
    (2)抽象工厂模式:每个抽象工厂派生多个具体工厂类,每个具体工厂负责多个(一系列)具体产品的实例创建。

    4.示例

    抽象工厂

    #import <Foundation/Foundation.h>
    @class AFOperation;
    typedef NS_ENUM(NSInteger, AFFactoryProductType){
        AFFactoryProductTypeMantou,
        AFFactoryProductTypeYoutiao,
    };
    @interface AFFactory : NSObject
    + (instancetype)factoryWithType:(AFFactoryProductType)type;
    - (AFOperation *)createProduct;
    @end
    
    #import "AFFactory.h"
    #import "AFFactoryMantou.h"
    #import "AFFactoryYoutiao.h"
    #import "AFOperation.h"
    @implementation AFFactory
    + (instancetype)factoryWithType:(AFFactoryProductType)type
    {
        AFFactory *factory;
        switch (type) {
            case AFFactoryProductTypeMantou:
                factory = [[AFFactoryMantou alloc] init];
                break;
            case AFFactoryProductTypeYoutiao:
                factory = [[AFFactoryYoutiao alloc] init];
                break;
            default:
                break;
        }
        return factory;
    }
    - (AFOperation *)createProduct{
        return nil;
    }
    @end
    

    抽象产品

    #import <Foundation/Foundation.h>
    @interface AFOperation : NSObject
    @property (nonatomic, copy, readonly)NSString *product;
    - (void)productBreakfast;
    @end
    
    #import "AFOperation.h"
    
    @implementation AFOperation
    - (void)productBreakfast{
    }
    @end
    

    具体工厂

    #import "AFFactory.h"
    @interface AFFactoryMantou : AFFactory
    
    @end
    
    #import "AFFactoryMantou.h"
    #import "AFOperationMantou.h"
    @implementation AFFactoryMantou
    - (AFOperation *)createProduct{
        return [[AFOperationMantou alloc] init];
    }
    @end
    
    #import "AFFactory.h"
    @interface AFFactoryYoutiao : AFFactory
    
    @end
    
    #import "AFFactoryYoutiao.h"
    #import "AFOperationYoutiao.h"
    @implementation AFFactoryYoutiao
    - (AFOperation *)createProduct{
        return [[AFOperationYoutiao alloc] init];
    }
    @end
    

    具体产品

    #import "AFOperation.h"
    @interface AFOperationMantou : AFOperation
    
    @end
    
    #import "AFOperationMantou.h"
    
    @implementation AFOperationMantou
    - (void)productBreakfast{
        NSLog(@"馒头");
    }
    @end
    
    #import "AFOperation.h"
    
    @interface AFOperationYoutiao : AFOperation
    
    @end
    
    #import "AFOperationYoutiao.h"
    @implementation AFOperationYoutiao
    - (void)productBreakfast{
        NSLog(@"油条");
    }
    @end
    

    使用AFFacytory来创建工厂,屏蔽了内部的实现,你可以不用管内部是使用的馒头工厂还是油条工厂。你需要关注的就是他们公有的接口就行了。抽象工厂的最大好处在于,让你感觉不到内部差异性。cocoa框架里到处都是使用了这种设计。比如NSString、NSNumber。(这方面可以查阅cocoa的类簇这个概念来了解相关资料)当然,缺点就是,如果你修改了抽象类的方法,那么所有的子类都要跟着一起修改。

    相关文章

      网友评论

          本文标题:iOS 设计模式(四)-工厂模式

          本文链接:https://www.haomeiwen.com/subject/bhgiqrtx.html