欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式-工厂模式

程序员文章站 2022-06-13 15:33:11
...

写在前面

这一篇主要是对比,工厂方法模式比简单工厂模式好在哪里?为什么要用这个模式?这个模式的精髓在哪里?

简单工厂模式

以计算器为例,UML类图如下:
设计模式-工厂模式
加减乘除运算都是继承自基类运算类,然后工厂类来调用这些运算,创建相应的对象,从而进行操作,oc代码如下:

抽象运算类:

#import <Foundation/Foundation.h>

@interface ZYCount : NSObject
@property (nonatomic, assign) double numberA;
@property (nonatomic, assign) double numberB;
- (instancetype)initWithNumberA:(double)numberA numberB:(double)numberB;

/**
 *  由于不知道子类的具体运算,所以,这个方法交给子类去实现即可(又由于此方法,所有子类都会有此一次运算,而不是某个子类所特有的,所以放到基类里最合适)
 *
 */
- (double)resultForCount;
@end


#import "ZYCount.h"

@interface ZYCount ()
@end

@implementation ZYCount
- (instancetype)initWithNumberA:(double)numberA numberB:(double)numberB
{
    if (self = [super init]) {
        _numberA = numberA;
        _numberB = numberB;
    }
    return self;
}

@end

加法运算类:

#import "ZYCount.h"

@interface ZYCountAdd : ZYCount
@end


#import "ZYCountAdd.h"

@implementation ZYCountAdd
- (double)resultForCount
{
    return self.numberA + self.numberB;
}
@end

减法类:

#import "ZYCount.h"

@interface ZYCountSubtractor : ZYCount

@end


#import "ZYCountSubtractor.h"

@implementation ZYCountSubtractor
- (double)resultForCount
{
    return self.numberA - self.numberB;
}
@end

乘法类:

#import "ZYCount.h"

@interface ZYCountMuli : ZYCount

@end


#import "ZYCountMuli.h"

@implementation ZYCountMuli
- (double)resultForCount
{
    return self.numberA * self.numberB;
}
@end

除法类:

#import "ZYCount.h"

@interface ZYCountDivision : ZYCount

@end


#import "ZYCountDivision.h"

@implementation ZYCountDivision
- (double)resultForCount
{
    if (self.numberB == 0) {
        NSLog(@"除数为0,产出错误");
        return 0;
    }
    return self.numberA / self.numberB;
}
@end

工具类/工厂类:

#import <Foundation/Foundation.h>

@class ZYCount;

@interface ZYCountTool : NSObject
+ (ZYCount *)creatCountForOperation:(NSString *)operationStr;
@end

#import "ZYCountTool.h"
#import "ZYCountAdd.h"
#import "ZYCountSubtractor.h"
#import "ZYCountMuli.h"
#import "ZYCountDivision.h"
@implementation ZYCountTool
+ (ZYCount *)creatCountForOperation:(NSString *)operationStr
{
    if ([operationStr isEqualToString:@"+"]) {
        return [[ZYCountAdd alloc] init];
    }
    else if ([operationStr isEqualToString:@"-"]) {
        return [[ZYCountSubtractor alloc] init];
    }
    else if ([operationStr isEqualToString:@"*"]) {
        return [[ZYCountMuli alloc] init];
    }

    return [[ZYCountDivision alloc] init];
}
@end

controller里面代码:

#import "ViewController.h"
#import "ZYCountAdd.h"
#import "ZYCountSubtractor.h"
#import "ZYCountMuli.h"
#import "ZYCountDivision.h"
#import "ZYCountTool.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    ZYCountAdd *p = (ZYCountAdd *)[ZYCountTool creatCountForOperation:@"+"];
    p.numberA = 10;
    p.numberB = 20;
    NSLog(@"%lf",[p resultForCount]);
}

@end

从这样的结构来看,可以知道,当我想要增加需求,比如说,其m的n次方的时候,需要增加一个运算类的子类,然后还需要更改工具类里面的代码,使得其支持这样新的运算对象的生成。这样,不仅扩展是开放的,修改也开放了,违背了,“开放-封闭原则”。

工厂模式

而采用工厂方法模式,可以解决这个问题。除了viewController里面代码和工厂类的代码需要改动,运算类的代码是一样的

改动代码如下:

设计模式-工厂模式

我们把工厂类抽象出一个接口,这个接口只有一个方法,就是创建抽象产品的工厂方法。然后,所有的要生成具体类的工厂,就去实现这个接口,这样一个简单工厂模式的工厂类,变成了一个工厂抽象接口和多个生成具体对象的工厂,于是我们增加‘求M的N次方’的功能时,就不需要更改原有的工厂类,只需要增加此功能的运算类和相应的工厂类就可以了。

抽象工厂基类:

#import <Foundation/Foundation.h>

@class ZYCount;

@interface ZYCountTool : NSObject
+ (ZYCount *)createOperation;
@end


#import "ZYCountTool.h"
@implementation ZYCountTool
@end
#import "ZYCountTool.h"

@interface ZYAddTool : ZYCountTool

@end


#import "ZYAddTool.h"
#import "ZYCountAdd.h"

@implementation ZYAddTool
+ (ZYCount *)createOperation
{
    return [[ZYCountAdd alloc] init];
}
@end
#import "ZYCountTool.h"

@interface ZYSubtractorTool : ZYCountTool

@end


#import "ZYSubtractorTool.h"
#import "ZYCountSubtractor.h"
@implementation ZYSubtractorTool
+ (ZYCount *)createOperation
{
    return [[ZYCountSubtractor alloc] init];
}
@end
#import "ZYCountTool.h"

@interface ZYMuliTool : ZYCountTool

@end


#import "ZYMuliTool.h"
#import "ZYCountMuli.h"
@implementation ZYMuliTool
+ (ZYCount *)createOperation
{
    return [[ZYCountMuli alloc] init];
}
@end
#import "ZYCountTool.h"

@interface ZYDivisionTool : ZYCountTool

@end


#import "ZYDivisionTool.h"
#import "ZYCountDivision.h"

@implementation ZYDivisionTool
+ (ZYCount *)createOperation
{
    return [[ZYCountDivision alloc] init];
}
@end
#import "ViewController.h"
#import "ZYCountAdd.h"
#import "ZYCountSubtractor.h"
#import "ZYCountMuli.h"
#import "ZYCountDivision.h"
#import "ZYCountTool.h"
#import "ZYAddTool.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    ZYCountAdd *p = (ZYCountAdd *)[ZYAddTool createOperation];
    p.numberA = 10;
    p.numberB = 20;
    NSLog(@"%lf",[p resultForCount]);
}
@end

以这样的模式来设计运算操作的代码,可以清楚的得知,当需要增加一个m的n次方的运算时,只需要继承运算类增加一个子类,继承工具类增加一个子类,就可以轻松实现了,从而避免的简单工厂里面那种要去修改工具类的方法,也就符合了开放-封闭原则(ocp)。

仔细观察就会发现,工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断转移到了viewController里面来进行,你想要增加功能,本来是修改工厂类的,而现在时修改viewController。

那么还是要修改viewController?尽管换成其他运算类,还是要修改,但是只需修改一处就可以了,比简单工厂方法好很多了。

总结

工厂方法模式客服了简单工厂模式中违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。工厂方法是简单工厂模式的进一步抽象和推广,由于使用多态性,工厂模式保持了简单工厂模式的优点,而客服了它的缺点。但缺点就是每增加一个产品,就需要增加一个产品工厂类,增加了额外的开发量。

解决方案:简单工厂模式+反射机制