架构设计(设计模式-工厂模式)

为什么使用工厂模式?

为了解除主程序和客户端耦合

  • 案例一:

    image
image

主程序和客户端就发生了耦合,对这个类的依赖性很高.

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:638302184,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 与2800+iOS开发者一起交流学习成长!

image

客户端 与UIButton 和 客户端与UIImageView之间存在依赖关系.
如果我们项目越来越大,我们的model层不能写在客户端.接着下一个案例,进行改造.

  • 案例二:

    image
image
image

上面的案例中,我们知道工厂帮我们实例化对象,减少与客户端之间的交互,降低了耦合度

记得小时候吃月饼,平常是家里自己配馅,和面,到最后的加工完成.如果做得多了,是挺麻烦的.这个时候,我们就可以交给工厂给我们加工,我们直接可以获取加工后的月饼.这就是所说的工厂模式.

案例二是不是有需要改进的地方呢?当然是有的.在return 的实例化对象中,我们已经固定了该实例化对象.如果我们想创建一组或者一类对象,就没有了好的扩展性.我们接着继续改进.

  • 案例三:
image
image
image

根据条件,创建实例,model和View之间进行解耦.

image

客户端依赖工厂,工厂实例化按钮,图片对象,客户端与按钮类,图片类进行了解耦合.我们的这个案例是否有问题?

是存在问题的,因为我们加了很多个判断,如果我们判断多了,几千几百个,我们要加几百个,几千个.所以我们继续改造.

  • 案例四: 动态创建实例对象,我不需要多个判断,一个判断我都不要,我就根据条件进行实例化.
image
image
image
image

我们对工厂类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文件,这样处理之后,我们再动态创建实例对象.

其实呢,如果你若了解了工厂模式,
感觉我们要成为好朋友.
又加深了交流,
感觉有熟悉了一些.
希望大家继续关注我,
文章会继续更新.

文章来源于网络,如有侵权,请联系小编删除。


推荐阅读更多精彩内容