为什么使用工厂模式?
为了解除主程序和客户端耦合
-
案例一:
创建Button和UIImageView.png
UML建模图.png主程序和客户端就发生了耦合,对这个类的依赖性很高.
客户端 与UIButton 和 客户端与UIImageView之间存在依赖关系.
如果我们项目越来越大,我们的model层不能写在客户端.接着下一个案例,进行改造.
-
案例二:
创建工厂类与Button类.png
上面的案例中,我们知道工厂帮我们实例化对象,减少与客户端之间的交互,降低了耦合度
记得小时候吃月饼,平常是家里自己配馅,和面,到最后的加工完成.如果做得多了,是挺麻烦的.这个时候,我们就可以交给工厂给我们加工,我们直接可以获取加工后的月饼.这就是所说的工厂模式.
案例二是不是有需要改进的地方呢?当然是有的.在return 的实例化对象中,我们已经固定了该实例化对象.如果我们想创建一组或者一类对象,就没有了好的扩展性.我们接着继续改进.
- 案例三:
屏幕快照 2018-03-19 下午10.10.04.png根据条件,创建实例,model和View之间进行解耦.
客户端依赖工厂,工厂实例化按钮,图片对象,客户端与按钮类,图片类进行了解耦合.我们的这个案例是否有问题?
是存在问题的,因为我们加了很多个判断,如果我们判断多了,几千几百个,我们要加几百个,几千个.所以我们继续改造.
- 案例四: 动态创建实例对象,我不需要多个判断,一个判断我都不要,我就根据条件进行实例化.
我们对工厂类04进行改造,我们用单例模式(GCD)实例化对象
我们使用集合存储类或者字典存储进行动态获取按钮类或者图片类,然后我们动态创建实例对象.
- 案例五: 通过创建配置文件,进行工厂模式开发,不需要修改代码,只对配置进行改造,再一次升级.
首先,我们创建项目,然后创建工厂类ViewFactory
#import <Foundation/Foundation.h>
@interface ViewFactory : NSObject
+(instancetype)sharedInstance;
-(NSObject *)createView:(NSString *)chose;
@end
#import "ViewFactory.h"
#import "ParserXmlParser.h"
@interface ViewFactory()
@property (nonatomic)NSMutableDictionary *dic;
@end
@implementation ViewFactory
//解决方案:集合存储类(key-value字典存储)
//GCD--创建单例
static ViewFactory * instance = nil;
+(instancetype)sharedInstance{
static dispatch_once_t once;
dispatch_once(&once, ^{
instance = [[ViewFactory alloc]init];
});
return instance;
}
+(instancetype)allocWithZone:(struct _NSZone *)zone{
if(instance == nil){
static dispatch_once_t once;
dispatch_once(&once, ^{
instance = [super allocWithZone:zone];
});
}
return instance;
}
- (instancetype)init
{
self = [super init];
if (self) {
//当我们的工厂创建成功,立马加载配置文件
ParserXmlParser *parser = [[ParserXmlParser alloc]init];
_dic = [parser parser];
}
return self;
}
-(NSObject *)createView:(NSString *)chose{
//动态实例化对象
return [[NSClassFromString([_dic objectForKey:chose])alloc]init];
}
@end
工厂类通过使用GCD创建单例,通过解析xml获取创建视图对象,最后通过动态实例化对象,开启工厂模式,不需要修改代码,只需要配置xml文件就可以动态创建视图对象.是不是挺牛........
然后创建视图类Button
#import <Foundation/Foundation.h>
@interface LKUIButton : NSObject
@end
#import "LKUIButton.h"
@implementation LKUIButton
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"创建了UIButton");
}
return self;
}
@end
再创建视图类UIImageView
#import <Foundation/Foundation.h>
@interface LKUIImageView : NSObject
@end
#import "LKUIImageView.h"
@implementation LKUIImageView
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"创建了UIImageView");
}
return self;
}
@end
创建我们的xml配置文件(ViewFactory.xml)
<?xml version="1.0" encoding="UTF-8"?>
<views>
<bean chose="1" class="LKUIButton"/>
<bean chose="2" class="LKUIUIImageView"/>
</views>
xml文件进行配置,视图中获取bea标签,从而获取chose,以及类,通过NSClassFromString创建实例化对象
最后呢,对我们的xml文件进行解析
#import <Foundation/Foundation.h>
@interface ParserXmlParser : NSObject
-(NSMutableDictionary*)parser;
@end
#import "ParserXmlParser.h"
@interface ParserXmlParser()<NSXMLParserDelegate>
@property (nonatomic)NSMutableDictionary *dic;
@end
@implementation ParserXmlParser
- (instancetype)init
{
self = [super init];
if (self) {
_dic = [[NSMutableDictionary alloc]init];
}
return self;
}
-(NSMutableDictionary *)parser{
//绑定delegate
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"ViewFactory" ofType:@".xml"];
NSURL *url = [[NSURL alloc]initFileURLWithPath:filePath];
NSXMLParser *xmlParser = [[NSXMLParser alloc]initWithContentsOfURL:url];
xmlParser.delegate = self;
//解析
[xmlParser parse];
return _dic;
}
-(void)parser:(NSXMLParser *)parser didStartElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(nonnull NSDictionary<NSString *,NSString *> *)attributeDict{
//解析xml
if ([elementName isEqualToString:@"bean"]){
NSString *chose = [attributeDict objectForKey:@"chose"];
NSString *className = [attributeDict objectForKey:@"class"];
[_dic setObject:className forKey:chose];
}
}
@end
解析xml文件,需要获取xml路径,调用代理,开启解析.通过
-(void)parser:(NSXMLParser *)parser didStartElement:(nonnull NSString *)elementName namespaceURI:(nullable NSString *)namespaceURI qualifiedName:(nullable NSString *)qName attributes:(nonnull NSDictionary<NSString *,NSString *> *)attributeDict
代理方法,解析出配置文件中带有bean
标签的所有值,set值到字典中,进一步我们解析获取的字典就可以,动态判断是哪个视图被我们创建了.
那么我们在swift项目中如何实现案例五呢?
案例六:创建Swift--工厂模式
创建工厂类
import Foundation
class ViewFactory:NSObject{
private var dic :NSMutableDictionary?
override init() {
super.init()
let xmlParserFactory = ViewXmlParser()
self.dic = xmlParserFactory.viewParser()
}
func createView(chose:String) -> NSObject! {
let className:String = self.dic?.object(forKey: chose) as! String
if let appName: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as! String?{
//获取控制器名
let classStringName = "\(appName).\(className)"
//将控制名转换成类
let classType = NSClassFromString(classStringName) as? NSObject.Type
if classType != nil{
return (classType?.init())!
}
}
return nil
}
}
创建视图对象Button
import Foundation
class LKUIButton:NSObject {
override init() {
super.init()
print("创建了UIButton")
}
}
创建视图对象ImageView
import Foundation
class LKUIImageView:NSObject {
override init() {
super.init()
print("创建了UIImageView")
}
}
创建及配置xml文件
<?xml version="1.0" encoding="UTF-8"?>
<views>
<bean chose="1" class="LKUIButton"/>
<bean chose="2" class="LKUIUIImageView"/>
</views>
解析xml文件
import Foundation
class ViewXmlParser: NSObject,XMLParserDelegate {
var dic:NSMutableDictionary?
override init() {
super.init()
self.dic = NSMutableDictionary()
}
func viewParser() -> NSMutableDictionary {
//创建解析器
let filePath = Bundle.main.path(forResource: "ViewFactory", ofType: ".xml")
let url:URL = URL(fileURLWithPath: filePath!)
let xmpParser:XMLParser = XMLParser(contentsOf: url)!
//绑定delegate(回调)
xmpParser.delegate = self
return self.dic!
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
if(elementName == "bean"){
//直接取出
let chose:String = attributeDict["chose"]!
let className :String = attributeDict["class"]!
self.dic?.setObject(className,forKey:chose as NSCopying)
}
}
}
从案例五与案例六中,我们知道swift的版本和oc版本的工厂模式是一样的.
通过创建配置文件,对配置文件解析,获取视图实例对象,进行动态创建实例化对象.
总结
通过对案例1-6,你可以重新认识工厂模式,原来工厂模式这么有意思,不深入了解一下,你只知道工厂模式存在,不知道工厂模式的使用.
- 案例一:
我们创建一个实例化对象,当创建多个的时候,问题就出来,类与类之间的耦合度比较高. - 案例二:
进行升级,通过简单的工厂模式改造,我们降低了耦合度,但是也存在问题,就是已经把创建的实例对象给固定了,也不好. - 案例三:
进行再次升级,我们创建的时候,可以进行判断,然后选择创建的实例对象.当然这一种比前两种要好.它存在什么问题呢?如果我们创建的对象几千几万,我们就要一个一个的处理,我们还要继续升级 - 案例四:
我们只需要使用集合存储类或者字典存储类,我们就可以动态创建实例对象,我们当然还可以升级 - 案例五:
我们通过配置xml文件进行改造,我们减少了代码的修改,从而只需要配置xml文件,这样处理之后,我们再动态创建实例对象. - 案例六:
swift版本,我们通过配置xml文件进行改造,我们减少了代码的修改,从而只需要配置xml文件,这样处理之后,我们再动态创建实例对象.
其实呢,如果你若了解了工厂模式,
感觉我们要成为好朋友.
又加深了交流,
感觉有熟悉了一些.
接下来,我们要进行工厂模式案例开发,
结合现在项目中开发场景使用.
希望大家继续关注我,
文章会继续更新.
网友评论