美文网首页
3.架构设计(设计模式-工厂模式)

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

作者: 木子心语 | 来源:发表于2018-03-21 23:43 被阅读0次

    为什么使用工厂模式?

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

    • 案例一:


      创建Button和UIImageView.png
    实例化对象.png

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

    UML建模图.png

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

    • 案例二:


      创建工厂类与Button类.png
    工厂类.h.png 工厂类.m.png

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

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

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

    • 案例三:
    创建工厂类,按钮,图片类.png 屏幕快照 2018-03-19 下午10.10.37.png 屏幕快照 2018-03-19 下午10.10.50.png

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

    屏幕快照 2018-03-19 下午10.10.04.png

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

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

    • 案例四: 动态创建实例对象,我不需要多个判断,一个判断我都不要,我就根据条件进行实例化.
    案例四.png 工厂类.h.png 工厂类1.m.png 工厂类2.m.png

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

    其实呢,如果你若了解了工厂模式,
    感觉我们要成为好朋友.
    又加深了交流,
    感觉有熟悉了一些.
    接下来,我们要进行工厂模式案例开发,
    结合现在项目中开发场景使用.
    希望大家继续关注我,
    文章会继续更新.

    相关文章

      网友评论

          本文标题:3.架构设计(设计模式-工厂模式)

          本文链接:https://www.haomeiwen.com/subject/bvqmqftx.html