创建型模式之工厂模式

173 阅读4分钟

设计模式预览

首先看看整体的设计模式类型:

设计模式

简单工厂模式

现在有个需求:需要根据客户的要求绘制不同的规则形状

开干,一顿撸代码

//创建圆
- (void)createCircle{

}
//创建方形
- (void)createRect
{
    
}
//创建角
- (void)createAngle
{
    
}

可能写到这你会感觉那是菜鸟才那么写呢,作为一个多年开发经验的牛逼程序员是知道程序需要复用的,那么第二种写法来了

Class Circle:
- (instance)drawCircle;

Class Rect:
- (instance)drawRect;

Class Angle:
- (instance)drawAngle

等客户发过需求来的时候,根据他的需要我判断创建实例,调用方法创建就是了, 然后一堆判断来了

//drawStr代表客户需要你绘制的图形
- (void)draw:(NSString *)drawStr
{
   if(drawStr == "圆"){
     circle = Circle()
   } 
   if(drawSre == "角"){
     angle = Angle()
   }
   .....
}

到这没什么问题啊,完全能实现客户的需求,但是会有两个问题:

  • 你的调用不但知道了接口,同时还知道了具体的实现类,违背了"开闭原则"
  • 如果客户还想创建别的形状,一堆if判断,看着就发毛

如果你的代码是当做接口提供给别人使用的话,那就糟糕了,人家可以随便给你霍霍,何况这么调用也很麻烦,对于别人来说,只想根据传入的形状类型得到想要的形状,具体怎么实现的?谁实现的?不关心.那么怎么解决呢?

用简单工厂模式来解决问题

要点:需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无需知道创建细节

如何做呢:

定义一个工厂类,可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类

由上面的做法大家可以总结出简单工厂模式的几个角色:

  • Factory(工厂角色): 即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象,提供工厂方法,它的返回类型为抽象产品类型Product

  • Product(抽象产品角色): 它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入使得在工厂类中只需定义一个统一的工厂方法,因为所有创建的具体产品对象都是其子类对象

  • ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个类的实例,每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法

用模式重新实现

1. 定义抽象类和公有方法

Class Shape:
- (instance)draw<pre>

2. 定义具体类并实现公有方法

Class Circle:Shape
- (instance)draw
{
  print("绘制圆")
}

Class Rect:Shape
- (instance)draw{

}

Class Angle:Shape
- (instance)draw{

}

3. 定义工厂

- (Shape *)drawShapeWithStr:(NSString *)shapeStr{
   Shape *shape = nil
   if(shapeStr == "圆"){
     shape = [Circle new]
   }
   if(shapeStr =="角"){
    shape =[Angle new]
   }
   ....
   shape.draw()
   return shape
}

完美实现,可能有人认为上面的简单工厂模式不就是把客户端的实现类移动到工厂类里吗? 这里解释一下:我们知道接口是用来封装隔离具体的实现的,目的就是不要让客户端知道封装提内部的具体实现.工厂的位置是位于封装体内的,也就是工厂是跟接口和具体的实现类在一起的,算是封装体内部的一个类,所以工厂知道具体的实现类是没有关系的

现在有一个非常大的问题?(新增实现类问题)

如何解决:

  • 使用配置文件,当有了新的实现类过后,只要在配置文件里面配置上新的实现类就好了
 -(Shape *)getShape:(ShapeType)shapeType
 {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"shape.plist" ofType:nil];
    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:path];
    NSString *shapeName = dic[@(shapeType)];
    Shape *shape = (Shape *)NSClassFromString(shapeName);
    if ([shape isKindOfClass:[Shape class]] && shape) {
        return  shape;
    }else{
        return nil;
    }
 }

如果新添加了实现类,修改配置文件就可以了,就不需要修改工厂类了,遵循了"开闭原则"

  • 直接使用实现类字符串
-(Shape *)selectCpuWithType:(NSString *)type
{
    Shape *shape = (Shape *)[NSClassFromString(type)new];
    if ([shape isKindOfClass:[Shape class]] && shape) {
        return  shape;
    }else{
        return nil;
    }
}

简单工厂模式的本质:

选择实现,其重点在于选择,实现是已经做好的.工厂的目的在于为客户端来选择相应的实现,使得客户端和实现之间解耦.如果实现发生了变化,也不用变动客户端,这个变化会被工厂吸收和屏蔽掉