工厂模式:定义创建对象的接口,让子类决定实例化哪一个类,工厂方法使得一个类的实例化延迟到其子类。
下列情况会适合使用工厂模式:
在Cocoa Touch框架中,NSNumber就是典型的工厂方法构造。NSNumber通过类方法numberWithBool:接口实例化NSCFBoolean实例,将bool值参数传递给实例化对象。
工厂方法模式的类结构图如下:
抽象的Product定义了创建对象的接口init。ConcreteProduct实现Product接口,返回自身的实例。Creator定义了返回Product对象的工厂方法。Creator可以有个一默认实现,返回默认的ConcreteProduct对象。ConcreteCreator是Creator的子类,重载工厂方法,返回ConcreteProduct的对象实例。创建时,根据ConcreteCreator实例来创建对应的ConcreteProduct实例,隐藏了ConcreteProduct的复杂创建过程。下面我们来用代码实现下工厂模式。
需求如下:实现一个画布页面背景,根据用户操作或者默认行为生成不同的背景图,背景图类型样式会随着需求不断的新增。
实现如下:
@interface XQCanvasView : UIView - (instancetype)initWithFrame:(CGRect)frame; @end 复制代码
XQCanvasView是背景图的父类,定义一个创建接口initWithFrame
@interface XQPaperCanvasView : XQCanvasView @end @implementation XQPaperCanvasView - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { UIImageView *imageView = [UIImageView new]; imageView.image = [UIImage imageNamed:@"paper.jpg"]; imageView.frame = frame; [self addSubview:imageView]; } return self; } @end 复制代码
XQPaperCanvasView实现父类的创建接口initWithFrame,增加纸纹理的背景
@interface XQClothCanvasView : XQCanvasView @end @implementation XQClothCanvasView - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { UIImageView *imageView = [UIImageView new]; imageView.image = [UIImage imageNamed:@"cloth.jpg"]; imageView.frame = frame; [self addSubview:imageView]; } return self; } @end 复制代码
XQClothCanvasView实现父类创建接口,增加布纹理的背景
@interface XQCanvasViewGenerator : NSObject - (XQCanvasView *)canvasViewWithFrame:(CGRect)frame; @end @implementation XQCanvasViewGenerator - (XQCanvasView *)canvasViewWithFrame:(CGRect)frame{ return [[XQCanvasView alloc] initWithFrame:frame]; } @end 复制代码
XQCanvasViewGenerator为生产者的父类,定义一个创建画布背景图XQCanvasView的接口。默认实现返回一个空白的XQCanvasView
@interface XQPaperCanvasViewGenerator : XQCanvasViewGenerator @end @implementation XQPaperCanvasViewGenerator - (XQCanvasView *)canvasViewWithFrame:(CGRect)frame{ return [[XQPaperCanvasView alloc] initWithFrame:frame]; } @end 复制代码
XQPaperCanvasViewGenerator实现父类的canvasViewWithFrame工厂方法,生成XQPaperCanvasView的纸纹理背景对象。
@interface XQClothCanvasViewGenerator : XQCanvasViewGenerator @end @implementation XQClothCanvasViewGenerator - (XQCanvasView *)canvasViewWithFrame:(CGRect)frame{ return [[XQClothCanvasView alloc] initWithFrame:frame]; } @end 复制代码
XQClothCanvasViewGenerator实现父类的canvasViewWithFrame工厂方法,生成XQClothCanvasView的布纹理背景对象。
上面就是所有工厂方法涉及的类,下面看使用:
@interface XQCanvasViewController : UIViewController - (void)loadCanvasViewWithGenerator:(XQCanvasViewGenerator *)generator; @end @interface XQCanvasViewController () @property (nonatomic, strong)XQCanvasView *canvasView; @end @implementation XQCanvasViewController - (void)viewDidLoad { [super viewDidLoad]; [self loadCanvasViewWithGenerator:[XQClothCanvasViewGenerator new]]; } - (void)loadCanvasViewWithGenerator:(XQCanvasViewGenerator *)generator{ [self.canvasView removeFromSuperview]; XQCanvasView *aCanvas = [generator canvasViewWithFrame:self.view.bounds]; self.canvasView = aCanvas; [self.view addSubview:aCanvas]; } @end 复制代码
画布视图控制器XQCanvasViewController定义了一个加载背景图的方法loadCanvasViewWithGenerator,供外部调用配置不同的背景图。在viewDidLoad中,调用[self loadCanvasViewWithGenerator:[XQClothCanvasViewGenerator new]];生成默认的布纹理背景图。loadCanvasViewWithGenerator方法实现中,先移除上一次的背景图self.canvasView,然后再用生成器generator生成对应的不同背景图。
当需求新增其他类型复杂的背景图时,只需新增对应的XQCanvasView背景图子类,与其对应的XQCanvasViewGenerator生成器子类,在调用的地方传递新生成的XQCanvasViewGenerator生成器子类即可。
工厂方法是在面向对象软件设计中应用非常普遍的设计模式。工厂方法从代码中消除了对应用特有类的耦合,只需处理产品Product的抽象接口即可。