Objective-C常用设计模式(一)--工厂方法模式

时间:2022-10-02 14:52:58
工厂方法模式:定义创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类。几乎所有面向对象语言写的应用程序都能看到工厂方法。 “专门定义一个类来负责创建其他类的实例,被创建的实例通常具有共同的父类。”

工厂方法模式使用场景:
  • 编译时无法准确预期要创建的对象的类;
  • 类想让其子类决定在运行时创建什么;
  • 类有若干辅助类为其子类,而你想将返回哪个子类这一信息局部化

结构图:


Objective-C常用设计模式(一)--工厂方法模式

ConcreteProduct1ConcreteProduct2两个产品具有一个共同的父类IProject,简单工厂类为SimpleFactory,负责根据传入的不同参数来决定生产ConcreteProduct1还是ConcreteProduct2产品。


代码例子如下:

Animal 类

@interface Animal :NSObject

@proterty(nonatomic,strong) NSString *name;

-(void)laugh;

@end

Dog类


@interface Dog:Animal

@end


Cat类

@interface Cat:Animal

@end


创建对象的工厂类

.h

@interface AnimalFactory:NSObject

+(Dog *)createDog;

+(Cat *)createCat;

@end

.m

@implementation AnimalFactory

+(Dog *)createDog{

    Dog *dog=[[Dog alloc]init];

    dog.name=@“baby”;

    return dog;

}


+(Cat *) createCat{

    Cat *cat=[[Cat alloc]init];

    return cat;

}

Main.m文件

Dog *dog=[AnimalFactory createDog];

Cat *cat=[AnimalFactory createCat];

这是简单工厂模式

现在创建100个Dog对象,如果这100个对象写在程序中的不同地方,按上边的方法是需要把Dog *dog=[AnimalFactory createDog];这一句话写在程序中很多不同的地方,那么现在有一个需求,就是如果需要把这些创建的100个Dog对象全部变成Cat对象,那么按照刚才的那个做法,就需要在这100句代码中把createDog方法变成createCat方法了,这样做还是很复杂

那么这个时候用工厂方法模式就能解决这个难题了

工厂方法模式是为每一个要创建的对象所在的类都相应地创建一个工厂

代码如下

@interface AnimalFactory:NSObject

-(Animal*)createAnimal;

@end;

Dog工厂类

@interface DogFactory:AnimalFactory;

@implementation DogFactory

-(Animal *)createAnimal{

retrurn [[Dog alloc]init];

}

@end

Cat工厂类

@interface CatFactory:AnimalFactory;

@implementation Cat Factory

-(Animal *)createAnimal

retrurn [[Cat alloc]init];

}

@end

Main.m

AnimalFactory *dogFactory=[[DogFactory alloc]init];


Animal *animal1=[dogFactory createAnimal];

[animal1 laugh];

Animal *animal2=[dogFactory createAnimal];

[animal2 laugh];

…….

Animal *animal100=[dogFactory createAnimal];

[animal100 laugh];

这样话如果要把100个Dog改为Cat的话,只需要吧DogFactory改为CatFactory就可以了


但是工厂方法也有它的限制:

1.要创建的类必须拥有同一个父类

2.要创建的类在100个不同的地方所调用的方法必须一样


例子 

Objective-C常用设计模式(一)--工厂方法模式

从最简单的简单工厂模式开始学起,举一个实现计算器的例子,来完成简单工厂模式。

一个简单计算器,用四则运算来考虑的话,加减乘除,那么初学者会觉得很简单,用if条件来进行判断,判断好了之后就可以完成要求,而稍微有经验点的 可能会选择switch case的判断方式,例如下面的代码:

Operation运算方法的逻辑

- (void)operationWithnumberA:(double )numberA Withoperator:(char)operator WithnumberB:(double )numberB
{
/** * 封装了一个传递值的方法 * * @param numberA 数字A * @param operator 运算符 * @param numberB 数字B */
    double result = 0;
    
    switch (operator) {
        case 'a':
        result = numberA + numberB;
            break;
            
        case 'b':
            result = numberA - numberB;
            break;
            
        case 'c':
            result = numberA * numberB;
            break;
            
            case 'd':
            if (numberB == 0) {
                NSLog(@"除数不能为0 请重新输入");
            }else{
                result = numberA / numberB;
            }
            
            case 'e':
            NSLog(@"退出");
            break;
            
        default:
            break;
    }

而客户端方面的代码 我们可以这么写

/** * 四则运算 */
- (void)operation

{
    char a ;
    
    double numberA;
    NSLog(@"请输入数字A");
    scanf("%lf",&numberA);
    double numberB;
    NSLog(@"请输入数字B");
    scanf("%lf",&numberB);
    
    NSLog(@"加法请输入a");
    NSLog(@"减法请输入b");
    NSLog(@"乘法请输入c");
    NSLog(@"除法请输入d");
    NSLog(@"退出请输入e");
    
    scanf("%c",&a);
    
    [self operationWithnumberA:numberA Withoperator:a WithnumberB:numberB];  
}

在我们得到需要的数值之后,调用运算方法做判断,算出结果。

这样写就会比if的判断清晰,因为我们已经把业务逻辑和界面显示的部分完全分离了,在任何需要用到的地方,我们就可以直接复制这段代码,完成运算。

但是假如,我有一天的运算需求不满足于四则运算,而是希望加上开根号或者平方的运算方法,该怎么办。难道我们还要回头,去switch语句里再加判断条件,之后在界面上增加提示么?

之前的代码,我们只用到了面向对象的三个特性之一,就是封装,而解决我上一段话提出的疑问,我们可以用到另外两个特性,多态和继承来实现。

为了实现之前的要求,在不改动其他代码的情况下,能够增加更多的运算方法,或者修改出问题的运算方法。那么我们首先先把四则运算,封装成四个类,即为加法类、减法类、乘法类、除法类。


@implementation AddOperation
/** * 加法 */
+ (double)addOperationWithNumberA:(double)numberA WithNumberB:(double)numberB
{
    double result = 0;
    
    result = numberA + numberB ;
    
    NSLog(@"%f",result);

    return result;
}




@implementation SubOperation

/** * 减法 */
+ (double)subOperationWithNumberA:(double)numberA WithNumberB:(double)numberB
{
    double result = 0;
    
    result = numberA - numberB ;
    
     NSLog(@"%f",result);
    
    return result;
}


@implementation MulOperation

/** * 乘法 */
+ (double)mulOperationWithNumberA:(double)numberA WithNumberB:(double)numberB
{
    double result = 0;
    
    result = numberA * numberB ;
    
     NSLog(@"%f",result);
    
    return result;
}

@implementation DivOperation

/** * 除法 */
+ (double)divOperationWithNumberA:(double)numberA WithNumberB:(double)numberB
{
    double result = 0;
    
    if (numberB == 0) {
        NSLog(@"除数不能为0 请重新输入");
    }else{
        result = numberA / numberB;
    }
    
     NSLog(@"%f",result);
    
    return result;
}

这样我们就已经把四则运算,封装成了四个类。因为偷懒,我并没有设计界面模型,只是把结果输出来,所以每段输出结果的NSLog请不要介意。

接下来,我们在简单工厂的Operation类中,把调用这四个类的运算方法实现。


/** * 封装了一个运算方法 * * @param numberA 数字A * @param operator 运算符 * @param numberB 数字B */
+ (void)operationWithnumberA:(double )numberA Withoperator:(char)operator WithnumberB:(double )numberB
{
    
    switch (operator) {
        case 'a':
            [AddOperation addOperationWithNumberA:numberA WithNumberB:numberB];
            break;
            
        case 'b':
            [SubOperation subOperationWithNumberA:numberA WithNumberB:numberB];
            break;
            
        case 'c':
            [MulOperation mulOperationWithNumberA:numberA WithNumberB:numberB];
            break;
            
        case 'd':
            [DivOperation divOperationWithNumberA:numberA WithNumberB:numberB];
            break;
        case 'e':
            NSLog(@"退出");
            break;
            
        default:
            break;
    }  
}

以上就是在简单工厂的类中,调用四个运算方法的类,来实现运算,并且成功解耦合,有利于以后的维护和扩展。客户端方面的代码也就非常简单。


/** * 四则运算 */
- (void)operation

{
    char a = 'a';
    
    double numberA = 10;
    
    double numberB = 20;
    
    
// NSLog(@"加法请输入a");
// NSLog(@"减法请输入b");
// NSLog(@"乘法请输入c");
// NSLog(@"除法请输入d");
// NSLog(@"退出请输入e");
    
    
    [Operation operationWithnumberA:numberA Withoperator:a WithnumberB:numberB];

}



有更好的请给我推荐推荐 谢谢。学习ing