zoukankan      html  css  js  c++  java
  • [设计模式]之一:简单工厂模式

    欢迎访问新博客wossoneri.com

    系列前言

    最近思考了一下这两年的工作:做Android的时候一直看Android知识,做iOS的时候一直学iOS的东西。其实看起来感觉这样没什么问题,但仔细想想,我发现自己一直忽略了一大片知识点,那就是软件工程。不同的语言,不同的开发方向的确在代码上有千差万别,但是回到软件架构上来看,所有的编程思想都是相通的,比如说算法,再比如说设计模式。算法这点可能在移动开发中用得较少,但设计模式是必不可少的。我回想了一下,虽说写了不少代码,也考虑过一些关于模块代码结构的设计,但还是缺乏对这一块的系统了解。所以就找了一本众人推荐的书——《大话设计模式》来看。这本书写的的确好,通俗易懂,所以在这里我也推荐一下。这本书看了几个章节我就有一种受人点拨的感觉,明显感觉到如果我把这本书吃透,编码水平肯定能提高一个level。想到我的读书列表还有几本受到程序员追捧的大作要看,突然有种迫不及待就要一本一本读下去的感觉。不过读书可不是读一遍就完事的,关键就在于悟。进步也不能急,一点一点来吧。加油!


    23种设计模式

    关于设计模式最好的书应该是GoF的《设计模式》了,其中列出了23种设计模式,这里先列出来,后面写完对应博客会把这里改为文章链接方便查看。

    1. Singleton 单件模式
    2. Abstract Factory 抽象工厂模式
    3. Builder 生成器模式
    4. Factory Method 工厂方法模式
    5. Prototype 原型模式
    6. Adapter 适配器模式
    7. Bridge 桥接模式
    8. Composite 组合模式
    9. Decorator 装饰模式
    10. Facade 外观模式
    11. Flyweight 享元模式
    12. Proxy 代理模式
    13. Template Method模板方法
    14. Command 命令模式
    15. Interpreter 解释器模式
    16. Mediator 中介者模式
    17. Iterator 迭代器模式
    18. Observer 观察者模式
    19. Chain Of Responsibility 职责链模式
    20. Memento 备忘录模式
    21. State 状态模式
    22. Strategy 策略模式
    23. Visitor 访问者模式
    24. Design Principles 设计原则

    实现四则运算

    下面直接先上代码,因为一开始就说太多概念容易让人看不下去。
    对于四则运算,也就是简单的加减乘除,实现起来并不难,但我们要用面向对象的角度去思考代码。加减乘除属于四种不同且独立的功能,所以应该分别地实现与封装,这样修改代码的时候也会方便一些,不会误改其他功能的代码。
    另外,对于这四种运算都有一个相同点,那就是运算都需要两个数字来完成,考虑到这一点,就可以设计一个基类,在基类中定义两个用于计算的变量,再声明一个获取计算结果的方法。之后,四则运算分别继承这个基类,各自实现返回结果的方法。

    ///Operation.h
    @interface Operation : NSObject
    
    @property (nonatomic, assign) CGFloat number1;
    @property (nonatomic, assign) CGFloat number2;
    
    - (CGFloat)getResult;
    
    @end
    ///Operation.m
    @interface Operation : NSObject
    
    @property (nonatomic, assign) CGFloat number1;
    @property (nonatomic, assign) CGFloat number2;
    
    - (CGFloat)getResult;
    
    @end
    ///OpAdd.h
    @interface OpAdd : Operation
    
    @end
    ///OpAdd.m
    @implementation OpAdd
    
    - (CGFloat)getResult {
        return self.number1 + self.number2;
    }
    
    @end
    ///OpMns.m
    @implementation OpMns
    
    - (CGFloat)getResult {
        return self.number1 - self.number2;
    }
    
    @end
    ///OpMul.m
    @implementation OpMul
    
    - (CGFloat)getResult {
        return self.number1 * self.number2;
    }
    
    @end
    ///OpDiv.m
    @implementation OpDiv
    
    - (CGFloat)getResult {
        if (self.number2 == 0) {
            NSLog(@"除数不能为零");
            return 0;
        } else {
            return self.number1 / self.number2;
        }
    }
    
    @end
    

    好了,功能封装完毕,下面就可以直接用这些写好的功能了,比如我要做加法

    Operation *operation = [OpAdd new];
    operation.number1 = 1;
    operation.number2 = 2;
    NSLog(@"operation result: %f", [operation getResult]);
    

    但这样做的话我每次做运算时都需要知道我到底要实例化谁。为了方便起见,可以设计一个工厂类,专门用来做这个实例化的过程,这就是简单工厂模式。

    typedef NS_ENUM(int, TYPE_OPERATION) {
        OPERATION_ADD = 0,
        OPERATION_MNS,
        OPERATION_MUL,
        OPERATION_DIV
    };
    
    @interface OperationSimpleFactory : NSObject
    
    + (Operation *)CreateOperationWithType:(enum TYPE_OPERATION)type;
    
    @end
    
    @implementation OperationSimpleFactory
    
    + (Operation *)CreateOperationWithType:(enum TYPE_OPERATION)type {
        
        Operation *op = nil;
        switch (type) {
            case OPERATION_ADD:
                op = [OpAdd new];
                break;
            case OPERATION_MNS:
                op = [OpMns new];
                break;
            case OPERATION_MUL:
                op = [OpMul new];
                break;
            case OPERATION_DIV:
                op = [OpDiv new];
                break;
            default:
                break;
        }
        return op;
    }
    
    @end
    

    设计好工厂就可以直接使用工厂类实例化合适的对象,通过多态,返回父类的方式实现运算。

    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // insert code here...
            Operation *op = [OperationSimpleFactory CreateOperationWithType:OPERATION_ADD];
            op.number1 = 10;
            op.number2 = 20;
            NSLog(@"operation result: %f", [op getResult]);
        }
        return 0;
    }
    

    这里工厂类的CreateOperationWithType:方法是类方法,所以使用的时候不需要实例化工厂类,直接使用该方法传入参数就能够获得对应的运算实例。

    但对于这段代码,如果我想要增加一个新的计算方法,比如用两个数字取log,这样我就需要首先创建一个计算log的功能类,然后修改工厂类的代码,增加一个switch分支。但是修改工厂类并不符合开放封闭原则,这里可以使用反射机制进行处理。

    static NSString *kOperationAdd = @"OpAdd";
    static NSString *kOperationMns = @"OpMns";
    static NSString *kOperationMul = @"OpMul";
    static NSString *kOperationDiv = @"OpDiv";
    
    @interface OperationSimpleFactory : NSObject
    
    + (Operation *)CreateOperationWithType:(NSString *)type;
    
    @end
    
    @implementation OperationSimpleFactory
    
    + (Operation *)CreateOperationWithType:(NSString *)type {
          return [NSClassFromString(type) new]; 
    }
    
    @end
    

    这里定义几个字符串常量,字符串内容和功能类名保持一致,将字符串作为参数即可。

    简单工厂模式

    简单工厂模式中定义一个抽象类,抽象类中声明公共的特征及属性,抽象子类继承自抽象类,去实现具体的操作。工厂类根据外界需求,在工厂类中创建对应的抽象子类实例并传给外界,而对象的创建是由外界决定的。外界只需要知道抽象子类对应的参数即可,而不需要知道抽象子类的创建过程,在外界使用时甚至不用引入抽象子类。

    简单工厂模式将操作对象的创建,和关于操作对象相关的业务逻辑分离开,降低操作对象的耦合度。由于工厂类只是为外界创建对象,所以并不需要实例化工厂类对象,只需要为外界提供类方法即可。外界需要什么类型的抽象子类,只需要传递对应的参数即可。

    UML类图

    UML

    小结

    在简单工厂模式中,一个工厂类负责所有产品对象的创建,这个工厂类的职责大大增加,可能客户端对于某些产品的创建方式会有不同的要求,这样的话,就要不断的修改工厂类,增加相应的逻辑,不利于后期的代码维护。
    另外,由于简单工厂模式使用静态方法创建,这就导致静态方法无法被继承。
    所以,简单工厂模式适用于创建的对象比较少或简单的情况。

    Swift代码

    因为最近也在看Swift,所以会用Swift做一些练习练习

    class Operation {
        var number1: CGFloat = 0.0
        var number2: CGFloat = 0.0
        
        func getResult() -> CGFloat {
            return 0
        }
    }
    
    class OpAdd: Operation {
        override func getResult() -> CGFloat {
            return self.number1 + self.number2
        }
    }
    
    class OpMns: Operation {
        override func getResult() -> CGFloat {
            return self.number1 - self.number2
        }
    }
    
    class OpMul: Operation {
        override func getResult() -> CGFloat {
            return self.number1 * self.number2
        }
    }
    
    class OpDiv: Operation {
        override func getResult() -> CGFloat {
            if self.number2 == 0 {
                print("除数不得为零")
                return 0
            } else {
                return self.number1 / self.number2
            }
        }
    }
    
    enum OperationType {
        case OperationAdd
        case OperationMns
        case OperationMul
        case OperationDiv
    }
    
    class OperationSimpleFactory {
        static func CreateOperationWithType(type: OperationType) -> Operation {
            var operation: Operation
            switch type {
            case .OperationAdd:
                operation = OpAdd()
            case .OperationMns:
                operation = OpMns()
            case .OperationMul:
                operation = OpMul()
            case .OperationDiv:
                operation = OpDiv()
            }
            
            return operation
        }
    }
    
    
    
    let op: Operation = OperationSimpleFactory.CreateOperationWithType(OperationType.OperationAdd)
    op.number1 = 10
    op.number2 = 20
    print("result by Add is", op.getResult())
    
  • 相关阅读:
    接口测试总结
    在 github 上获取源码
    推荐一个css帮助手册的版本 同时提供chm和在线
    由csdn开源项目评选中闹出刷票问题想到投票程序的设计
    由一个园友因为上传漏洞导致网站被攻破而得到的教训
    让 SVN (TortoiseSVN)提交时忽略bin和obj目录
    未能进入中断模式,原因如下:源文件“XXXXXX”不属于正在调试的项目。
    未能加载文件或程序集“XXXXX”或它的某一个依赖项。试图加载格式不正确的程序。
    .Net AppDomain.CurrentDomain.AppendPrivatePath(@"Libs");
    C# Remoting的一个简单例子
  • 原文地址:https://www.cnblogs.com/rossoneri/p/5487981.html
Copyright © 2011-2022 走看看