设计模式之创建型模式

前言

  前段时间看了《Head First设计模式》这本书,虽然没有看完,但常用的设计模式基本都看了一遍。刚开始看完基本都能理解,也能体会到设计模式的妙处,但是设计模式在平时工作中用得较少,一段时间后再来回忆看过的这些东西,基本上只能记住它们的名字,其他的都想不起来。所以准备再统一复习一遍常用的设计模式,顺便写点自己理解的东西,当做笔记吧,希望以后想不起来时再回来看能够迅速的想起。

正式开始

  言归正传,《Head First设计模式》这本书讲了23种设计模式,网上大致将这23种模式分为三类,分别为:

  • 创建型模式:指的是用来创建对象以便能从系统中解耦。
    有工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
  • 结构型模式:指的是通过各个对象来组成大规模的对象结构。
    有适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  • 行为型模式:指的是用来在对象之间管理算法、关系等。
    有策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

创建者模式

0.简单工厂模式

  简单工厂模式其实不算在23种设计模式中,但在平时开发中用的场景还是比较多的,而且和工厂方法模式、抽象工厂模式类似,所以还是先看下简单工厂模式。
  简单工厂模式有一个工厂、一类产品,外部调用并不关心产品是怎么创建的,它只需要告诉这个工厂,我需要什么类型的产品即可,具体创建逻辑由工厂内部处理。工厂会根据调用者传给它的类型进行产品的创建,关系图如下:
图1

举个栗子,经典的汽车生产:
首先,创建汽车基类:

@interface Car : NSObject

- (void)carInfomation;

@end

然后创建它的具体实现类:

@interface AudiCar : Car

@end

@implementation AudiCar

- (void)carInfomation {
    NSLog(@"I am AudiCar");
}

@end
@interface BenzCar : Car

@end

@implementation BenzCar

- (void)carInfomation {
    NSLog(@"I am BenzCar");
}

@end

最后创建工厂:

@implementation CarsFactory

+ (Car *)createCarWithType:(CarType)carType {
    Car *car;
    switch (carType) {
        case CarTypeAudi:
            car = [[AudiCar alloc] init];
            break;
        case CarTypeBenz:
            car = [[BenzCar alloc] init];
            break;
    }
    
    return car;
}

@end

外部调用者只需给工厂提供参数即可:

- (void)testSimpleFactory {
    // Audi
    Car *audi = [CarsFactory createCarWithType:CarTypeAudi];
    [audi carInfomation];
    
    // Benz
    Car *benz = [CarsFactory createCarWithType:CarTypeBenz];
    [benz carInfomation];
}

测试结果:

2018-01-03 21:39:41.834124+0800 DesignPatternDemo[1582:77442] I am AudiCar
2018-01-03 21:39:41.834264+0800 DesignPatternDemo[1582:77442] I am BenzCar
总结

  简单工厂模式可以将同一类型产品创建集中到工厂里,使用者无需知道产品的内部创建逻辑,只需提供产品的类型,工厂就可以创建出相应的产品。
  虽然简单工厂模式可以实现调用者跟产品之间的解耦,但是并不符合开闭原则,即产品的创建依赖于工厂类,每次添加一款新产品就得修改工厂内部的实现,产品越多switch(或者if-else)就越长。因此就有了工厂方法模式。

1.工厂方法模式

  工厂方法模式是创建一个工厂基类以及若干个具体工厂类,每个工厂只负责自己这款产品的创建,即每款产品有自己对应的一个工厂。这样如果新加一款产品不需要去修改之前工厂实现,只需再实现一个创建新产品的工厂。具体关系如下:
关系图2.

还是那个栗子:
汽车的结构不变,修改工厂的实现,首先创建一个工厂基类:

@interface CarBaseFactory : NSObject

+ (Car *)createCar;

@end

然后实现创建具体汽车的具体工厂:

@interface AudiCarFactory : CarBaseFactory

@end

@implementation AudiCarFactory

+ (Car *)createCar {
    AudiCar *car = [[AudiCar alloc] init];
    return car;
}

@end
@interface BenzCarFactory : CarBaseFactory

@end

@implementation BenzCarFactory

+ (Car *)createCar {
    BenzCar *car = [[BenzCar alloc] init];
    return car;
}

@end

外部调用者:

- (void)testFactoryMethod {
    // Audi
    Car *audi = [AudiCarFactory createCar];
    [audi carInfomation];
    
    // Benz
    Car *benz = [BenzCarFactory createCar];
    [benz carInfomation];
}

此时如果需要再加新的产品,就不需要再去改之前的代码,只需添加新的产品和创建该产品的工厂,代码如下:

新的汽车保时捷:

@interface PorscheCar : Car

@end

@implementation PorscheCar

- (void)carInfomation {
    NSLog(@"I am PorscheCar");
}

@end

保时捷汽车工厂:

@interface PorscheCarFactory : CarBaseFactory

@end

@implementation PorscheCarFactory

+ (Car *)createCar {
    PorscheCar *car = [[PorscheCar alloc] init];
    return car;
}

@end

外部调用者:

- (void)testFactoryMethod {
    // Audi
    Car *audi = [AudiCarFactory createCar];
    [audi carInfomation];
    
    // Benz
    Car *benz = [BenzCarFactory createCar];
    [benz carInfomation];
    
    // Porsche
    Car *porsche = [PorscheCarFactory createCar];
    [porsche carInfomation];
}

测试结果:

2018-01-03 22:11:46.448233+0800 DesignPatternDemo[1794:108045] I am AudiCar
2018-01-03 22:11:46.448372+0800 DesignPatternDemo[1794:108045] I am BenzCar
2018-01-03 22:11:46.448465+0800 DesignPatternDemo[1794:108045] I am PorscheCar
总结

  工厂方法模式通过每个工厂只负责一款产品的创建来解决简单工厂模式不符合开闭原则的缺点,但也带来了类文件过多的缺点(大多数设计模式都会有这个缺点),很多时候这些类文件都只实现很简单的功能。

3.抽象工厂模式

  抽象工厂模式是工厂方法模式的升级版,或者说工厂方法模式是抽象工厂模式的特例。在工厂方法模式中一个工厂只能创建一款产品,而在抽象工厂模式中一个工厂可以创建一个产品簇(即一个产品和这个产品的许多线下产品)。关系图如下:
关系图3.

还是那个栗子,各种不同的汽车可能对应着不同的配件,比如Audi配置着发动机A、空调A,Benz配置着发动机B、空调B。
首先定义发动机:

@interface Engine : NSObject

- (void)engineInfomation;

@end
@interface EngineA : Engine

@end

@implementation EngineA

- (void)engineInfomation {
    NSLog(@"I am EngineA");
}

@end
@interface EngineB : Engine

@end

@implementation EngineB

- (void)engineInfomation {
    NSLog(@"I am EngineB");
}

@end

定义空调:

@interface AirConditioner : NSObject

- (void)airConditionerInfomation;

@end
@interface AirConditionerA : AirConditioner

@end

@implementation AirConditionerA

- (void)airConditionerInfomation {
    NSLog(@"I am AirConditionerA");
}

@end
@interface AirConditionerB : AirConditioner

@end

@implementation AirConditionerB

- (void)airConditionerInfomation {
    NSLog(@"I am AirConditionerB");
}

@end

修改汽车类,添加发动机和空调属性:

@interface Car : NSObject

@property (nonatomic, strong) Engine *engine;

@property (nonatomic, strong) AirConditioner *airConditioner;

- (void)carInfomation;

@end

为工厂类添加创建发动机和空调的方法:

@interface CarBaseFactory : NSObject

+ (Car *)createCar;

+ (Engine *)createEngine;

+ (AirConditioner *)createAirConditioner;

@end
@implementation AudiCarFactory

+ (Car *)createCar {
    AudiCar *car = [[AudiCar alloc] init];
    return car;
}

+ (Engine *)createEngine {
    EngineA *engine = [[EngineA alloc] init];
    return engine;
}

+ (AirConditioner *)createAirConditioner {
    AirConditionerA *airConditioner = [[AirConditionerA alloc] init];
    return airConditioner;
}

@end
@implementation BenzCarFactory

+ (Car *)createCar {
    BenzCar *car = [[BenzCar alloc] init];
    return car;
}

+ (Engine *)createEngine {
    EngineB *engine = [[EngineB alloc] init];
    return engine;
}

+ (AirConditioner *)createAirConditioner {
    AirConditionerB *airConditioner = [[AirConditionerB alloc] init];
    return airConditioner;
}

@end

外部调用者调用:

- (void)testAbstractFactory {
    // Audi
    Car *audi = [AudiCarFactory createCar];
    audi.engine = [AudiCarFactory createEngine];
    audi.airConditioner = [AudiCarFactory createAirConditioner];
    [audi carInfomation];
    [audi.engine engineInfomation];
    [audi.airConditioner airConditionerInfomation];
    
    // Benz
    Car *benz = [BenzCarFactory createCar];
    benz.engine = [BenzCarFactory createEngine];
    benz.airConditioner = [BenzCarFactory createAirConditioner];
    [benz carInfomation];
    [benz.engine engineInfomation];
    [benz.airConditioner airConditionerInfomation];
}

测试结果:

2018-01-03 22:42:55.410243+0800 DesignPatternDemo[1958:151756] I am AudiCar
2018-01-03 22:42:55.410380+0800 DesignPatternDemo[1958:151756] I am EngineA
2018-01-03 22:42:55.410488+0800 DesignPatternDemo[1958:151756] I am AirConditionerA
2018-01-03 22:42:55.410605+0800 DesignPatternDemo[1958:151756] I am BenzCar
2018-01-03 22:42:55.410703+0800 DesignPatternDemo[1958:151756] I am EngineB
2018-01-03 22:42:55.410976+0800 DesignPatternDemo[1958:151756] I am AirConditionerB

总结

  工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。可以这么理解,抽象工厂就像一家完整的工厂,可以创建工厂里的各种产品,而工厂方法就像工厂里的一条产品线,只负责生产一款产品。

4.单例模式

  单例模式在iOS开发中相当重要,也相当常见。单例模式保证了在程序运行期间该对象只有一个实例。
示例代码:

@implementation CarPerformanceCenter

+ (instancetype)shareInstance {
    static CarPerformanceCenter *center;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        center = [[CarPerformanceCenter alloc] init];
    });
    
    return center;
}

@end

5.建造者模式、原型模式

  这两种设计模式平时用得较少,暂时不讨论,后面有时间再继续研究。

你可能感兴趣的:(设计模式之创建型模式)