美文网首页iOS开发笔记设计模式iOS 设计模式
工厂模式三部曲 - 工厂方法模式

工厂模式三部曲 - 工厂方法模式

作者: 刘小壮 | 来源:发表于2016-04-05 00:47 被阅读10960次
该文章属于<简书 — 刘小壮>原创,转载请注明:

<简书 — 刘小壮> http://www.jianshu.com/p/03519d5e47b6


紧接着上一篇文章开始写,这是本系列中的第二篇文章了,这篇文章主要讲一下工厂方法模式。在最后一篇抽象工厂模式的文章中,将会对这三篇文章进行一次总结。

这篇文章中并没有给出反射机制实现的代码,主要是因为工厂方法模式就是为了解决简单工厂模式的一些缺点,然而使用了反射机制的简单工厂模式已经不具备这些缺点,所以就不需要这篇文章中讲的内容了。这篇文章主要还是单一从设计模式的角度来讲一下这个模式,带大家认识一下这个设计模式。

本人理解可能不够深刻,这一系列文章中存在的问题,欢迎大家提出,谢谢!😊


博客配图

什么是工厂方法模式?

工厂方法模式和简单工厂模式十分类似,大致结构是基本类似的。不同在于工厂方法模式对工厂类进行了进一步的抽象,将之前的一个工厂类抽象成了抽象工厂和工厂子类,抽象工厂定义一个创建抽象子类的接口,抽象工厂的子类实现这些接口并决定实例化哪个抽象子类。工厂子类决定着创建哪个抽象子类,外界决定着创建哪种工厂子类,抽象子类和工厂子类是一一对应的

在工厂方法模式中,和简单工厂模式一样,对外隐藏了抽象子类的创建过程,外界只需要关心工厂类即可,负责实例化的工厂子类决定着最后的结果。

工厂方法模式主要包含四部分:
  • 工厂抽象类:定义创建抽象子类的接口,通过接口返回具体的抽象子类。
  • 工厂子类:继承自工厂抽象类,并重写父类的方法来创建对应的抽象子类。
  • 抽象类:定义抽象子类所需的属性和方法,子类通过继承自抽象类获得这些方法。
  • 抽象子类:继承自抽象类,实现具体的操作。
为什么要用工厂方法模式?

在简单工厂模式的代码中,如果我们没有使用反射机制,只是标准的简单工厂模式代码。会有一个问题,就是如果新增加其他运算功能,需要创建一个抽象子类,但是还需要修改工厂类中的代码逻辑,这种设计是不符合开放封闭原则的。开放封闭原则对于修改是关闭的,对于扩展是开放的。而且将所有的操作子类的判断和实例化都由一个工厂类完成,如果业务比较复杂会导致工厂类负担较重。

工厂方法模式将之前负责生成具体抽象子类的工厂类,抽象为工厂抽象类和工厂子类组成的一系列类。每创建一个抽象子类,就需要创建一个工厂子类,并且一一对应,由工厂子类去生成对应的抽象子类,由外界使用方来决定生成哪个工厂子类。这样在增加新的需求时,就不需要对工厂抽象类进行修改,而是对应新增的抽象子类创建对应的工厂子类即可。

业务场景

这里的业务场景还用之前简单工厂模式中提到的运算的例子,根据运算符的不同,计算两个值的结果。

UML类图

工厂方法模式

这张类图中增加了很多工厂子类,每一个抽象子类都对应着一个工厂子类。这样做的好处就是更佳灵活,每次新添加一个抽象子类,就生成一个工厂子类,对其他类没有任何影响。

简单工厂模式违背了开放封闭原则,每次添加和删除抽象子类的时候,都需要对工厂类进行操作,这样不仅对工厂类的扩展开放了,还开放了工厂类的修改,这就是违背开放封闭原则的。因为按照开放封闭原则,新增加一个需求,应该是在原有类的基础上进行扩展,而不是对原有类进行修改。这样整个模式在生成新算法类时,只是进行扩展而不对模式中原有的代码进行修改,这就是符合开放封闭原则的。

代码实现

工厂方法模式新建一个抽象子类时,选择算法的操作还是存在的,外界的灵活性依然存在,只是将原来由工厂类对抽象子类的创建,交给工厂子类去完成创建。之前增加和删除修改的是工厂类,现在是增加工厂子类,这也是开放封闭原则的一个体现。之前的简单工厂是在工厂类中创建抽象子类,工厂方法模式在工厂子类中创建抽象子类,依然封装了对象实例化的过程。

由于代码比较多,所以这里只贴出加法和减法运算的代码,其他运算代码类似。

创建运算抽象类,声明参与运算的两个属性和运算方法,下面的具体抽象子类继承自这个类。
@interface Operation : NSObject
@property (nonatomic, assign) CGFloat numberOne;
@property (nonatomic, assign) CGFloat numberTwo;
- (CGFloat)getResult;
@end

@implementation Operation
- (CGFloat)getResult {
    return 0;
}
@end

@interface OperationAdd : Operation
@end

@implementation OperationAdd
- (CGFloat)getResult {
    return self.numberOne + self.numberTwo;
}
@end

@interface OperationSub : Operation
@end

@implementation OperationSub
- (CGFloat)getResult {
    return self.numberOne - self.numberTwo;
}
@end
抽象工厂类,定义了实例化实际运算类的方法,由子类继承并实例化不同的运算类。
@interface Factory : NSObject
+ (Operation *)CreateOperation;
@end

@implementation Factory
+ (Operation *)CreateOperation {
    return nil;
}
@end

@interface FactoryAdd : Factory
@end

@implementation FactoryAdd
+ (Operation *)CreateOperation {
    return [OperationAdd new];
}
@end

@interface FactorySub : Factory
@end

@implementation FactorySub
+ (Operation *)CreateOperation {
    return [OperationSub new];
}
@end
外界使用时,直接实例化某个工厂子类即可,通过外界实例化某个工厂子类来选择具体的运算类。
- (void)viewDidLoad {
    Operation *oper = [FactoryAdd CreateOperation];
    oper.numberOne = 13;
    oper.numberTwo = 24;
    NSLog(@"result : %f", [oper getResult]);
}

当需求发生改变时,需要进行算法的切换,外界只需要将工厂子类调用类方法的类名换一下即可,其他地方都不用发生变化。这样做就像一个“开关”一样,在外界由这个工厂子类的类型控制着抽象子类的实例化类型,而我们并不知道抽象子类实例化的过程

工厂方法模式的优缺点

优点

工厂方法模式的的优点在于更大的灵活性,增加或删除某种运算都不会对其他地方造成影响,更佳符合开放封闭原则。

而且对抽象的使用更佳深入,将工厂类也抽象为了抽象工厂类和工厂子类,外界调用更加灵活,这也是对多态的一种体现。

缺点

工厂方法模式的缺点也是非常显而易见的,工厂方法模式中新增一个抽象子类,意味着工厂子类要跟着成对增加,这样会造成生成过多的类,工厂方法模式的复杂度也会随之增加。

对于这个缺点,反射机制当然可以很好的解决这个问题,工厂设计模式和反射机制的配合,可以使这种设计模式更佳易用和灵活,减少了条件判断和类的数量。

答疑解惑

使用工厂方法模式,看上去会感觉到这不是更麻烦了吗,直接在外界创建具体的抽象子类不行吗?还用这么麻烦的创建工厂子类,然后再用工厂子类去创建抽象子类。

我将从两方面回答这个问题:
  1. 假设现在项目比较大,在外界很多地方都直接使用了抽象子类直接进行运算,这种方式在写代码的时候确实很快也很爽。但是,假设有一天,产品经理过来说要改需求,我现在不要加减乘除这四种运算了,我要换成更高级的其他运算。。。如果这样改起来改动就大了,需要把所有直接使用抽象子类实例化的地方都做修改。

  2. 这只是一种设计模式的思路,在程序的开发中没有一种设计模式是万能的,在适合的地方用适合的设计模式,或根据业务需求自己制定一套模式,这才是最好的。只有最适合业务的模式,才是最好的模式


前段时间写了关于工厂模式的系列文章,这系列文章理解起来比较难懂。应广大读者的需要,这段时间专门给这系列文章补了Demo

Demo只是来辅助读者更好的理解文章中的内容,应该博客结合Demo一起学习,只看Demo还是不能理解更深层的原理Demo中代码都会有注释,各位可以打断点跟着Demo执行流程走一遍,看看各个阶段变量的值。

Demo地址刘小壮的Github

相关文章

  • 设计模式-3种工厂模式

    工厂模式包括:简单工厂模式,工厂方法模式,抽象工厂模式 简单工厂模式 工厂方法根据参数直接创建实例:工厂->产品 ...

  • 设计模式-工厂模式

    工厂模式概念 实例化对象,用工厂方法代替new操作。工厂模式包括工厂方法模式和抽象工厂模式。抽象工厂模式是工厂模式...

  • 设计模式 工厂模式

    工厂模式 工厂模式三大类1、简单工厂模式(静态工厂方法模式)2、工厂方法模式3、抽象工厂模式(Kit模式) 简单工...

  • 设计模式-工厂方法模式

    1、工厂方法模式(Factory Method) 工厂方法模式分为三种: 普通工厂模式 多个工厂模式 静态工厂模式...

  • 工厂模式

    工厂模式 就是工厂---生产-->产品 在设计模式中,分为 简单工厂模式, 工厂方法模式,抽象工厂模式. 工厂模式...

  • 第一章2.0工厂- 基础类准备

    2.1工厂-简单工厂模式2.2工厂-工厂方法模式2.3工厂-抽象工厂模式

  • 设计模式学习--工厂方法模式

    模式定义 工厂方法模式又称工厂模式,也叫虚拟构造器模式或者多态工厂模式,它属于类创建型模式。在工厂方法模式中,工厂...

  • PHP-浅谈单例模式和工厂模式

    PHP中常用的设计模式有单例模式、工厂模式(简单工厂模式、工厂方法模式和抽象工厂方法模式)、适配模式、策略模式。 ...

  • 建造模式

    包括:简单工厂、工厂方法、抽象工厂、单例模式、多例模式、建造模式、原始原型模式。 简单工厂:又名静态工厂方法模式,...

  • [Android]三种工厂模式总结。

    Android中,工厂模式分为三种:简单工厂模式、工厂方法模式、抽象工厂模式。 一.简单工厂模式。 定义:简单工厂...

网友评论

  • SuyChen:感觉开发中还是简单工厂实用一点也
    刘小壮:嗯,是的。一般不会用抽象工厂模式,虽然很强大,但是用起来比较复杂。
  • 5ee14485e803: 你好,工厂方法模式,其实直接用了工厂抽象子类,并没有用到工厂抽象类,所以是不是这个工厂抽象类不需要创建也可以
    刘小壮:@小雨的名字 是的,就像你说的,直接写两个工厂类理论上来说行得通。而且现有的工厂方法模式和后面的抽象工厂模式,都很臃肿。
    5ee14485e803:@刘小壮 就是直接写两个工厂类
    刘小壮:不创建工厂抽象类,那工厂抽象子类继承谁呢?
  • _moses:+ (Operation *)CreateOperation;这个方法有必要写吗?
    FactoryAdd *oper = [FactoryAdd new];
    oper.numberOne = 13;
    oper.numberTwo = 24;
    NSLog(@"result : %f", [oper getResult]);
    这样不就行了吗?为什么要多此一举用一个构造方法来初始化子类对象,直接初始化不就可以了吗???
    刘小壮:是开闭原则的一个体现,将Operation的创建封装起来。这样的代码也更利于扩展。
  • 阿琥123:诶 那如果是用工厂方法模式的话 楼主回答的第一个方面不是没有解决吗 不是还是要改使用运算地方的工厂子类吗
    刘小壮:@兔斯拉 好的
    阿琥123:哦 解决方法第三篇看到了 不好意思
  • reloadRen:- (void)viewDidLoad {
    Operation *oper = [FactoryAdd CreateOperation];
    在外部调用时,我看见是直接拿工厂子类去调用实例化方法,当前有多个工厂子类的话在引用头文件的时候都需要引用吗?
    刘小壮:@reloadRen 客气了 :blush:
    reloadRen:@刘小壮 非常感谢楼主分享和回复! :smiley: 本人小白一个,还需要自我加深理解下。
    刘小壮:@reloadRen 头文件还是要引的,设计模式主要体现在代码的设计上。
  • reloadRen:楼主你好 这个源码有吗?求分享
    刘小壮:@reloadRen 源码都在文章里,代码都经过调试,可以直接复制到你新建的项目中。

本文标题:工厂模式三部曲 - 工厂方法模式

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