zoukankan      html  css  js  c++  java
  • 设计模式工厂方法模式<二>

    前面的理论先不管了,直接解析代码。

    计算器程序的UML类图

     

    代码解析

    在讲解模式之前,先介绍两个辅助函数/对象

    View Code
    /**
     * 用于创建接口的类,并带有检查功能
     */
    var Interface = function(name, methods) {
        //检查参数个数
        if(arguments.length != 2) {
            //错误显示不能准确定位
            throw new Error('创建接口的对象需要2个参数:接口名,其方法名组成的数组');
        }
        //确保第二个参数是数组类型
        if(!(methods instanceof Array)) {
            throw new Error('创建接口的第二参数应为数组类型');
        }
        //为接口创建两个属性,并赋值
        this.name = name;
        this.methods = [];              //存储接口方法
        for(var i=0; methods[i]; i++) {
            if(typeof methods[i] !== 'string') {
                throw new Error('接口的方法名应为字符串');
            }
            this.methods.push(methods[i]);
        }
    };
    /**
     * 检查创建的实例是否存在接口中的所有方法
     * 使用方法:把此函数紧跟创建实例语句后面
     * @param {Object} object 实例
     * @param {multi} interfaces 接口列表
     */
    Interface.ensureImplement = function(object, interfaces) {
        //检查参数个数
        if(arguments.length < 2) throw new Error('接口类的静态ensureImplement方法参数不能少于2个');
        //子类实现的接口
        var intface = null;
        //检查子类是否实现了接口所有方法
        for(var i=1; arguments[i]; i++) {
            intface = arguments[i];
            //判断传递的参数是否都是合法的接口实例
            if(intface.constructor !== Interface) throw new Error('用ensureImplement检查时,发现'+intface+'不是合法的接口');
            //获取接口的所有方法
            var methods = intface.methods;
            //检查子类是否实现了接口中的所有方法
            for(var j=0; methods[j]; j++) {
                var method = methods[j];
                if(!object[method] || typeof object[method]!='function') {
                    throw new Error('没有实现'+intface.name+'接口的方法:'+method);
                }
            }
        }
    };

     创建接口的示例:

    //创建运算类接口
    var Operation = new Interface('Operation', ['getResult']);
    //-----------------------------------------------------
    //...
    IFactory.prototype.getResult = function(a, b) {
        var oper = this.factoryMethod();
        //判断实例是否实现了Operation接口中的所有方法
        Interface.ensureImplement(oper, Operation);
        return oper.getResult(a, b);
    };

    下面是辅助函数extend()用于继承操作

    View Code
    /**
     * 实现原型对象继承
     */
    var extend = function(subClass, superClass) {
        var F = function() {};
        F.prototype = superClass.prototype;
        subClass.prototype = new F();
        subClass.prototype.constructor = subClass;
        
        subClass.superclass = superClass.prototype;
        if(superClass.prototype.constructor === Object.prototype.constructor) {
            superClass.prototype.constructor = superClass;
        }
    };

     工厂方法模式实现计算器程序中所有的类统计:

    /*
     * 工厂方法
     * IFactory
     * AddFactory
     * SubFactory
     * MulFactory
     * DivFactory
     * 
     * Operation
     * OperationAdd
     * OperationSub
     * OperationMul
     * OperationDiv
     */

     创建运算类接口,并用各个运算符实现具体类。其中用到了接口。

    //创建运算类接口
    var Operation = new Interface('Operation', ['getResult']);
    //具体的实现接口的加法运算类
    var OperationAdd = function() {};           //implements Operation
    OperationAdd.prototype.getResult = function(a, b) {
        return a+b;
    };
    //减法运算类
    var OperationSub = function() {};           //implements Operation
    OperationSub.prototype.getResult = function(a, b) {
        return a-b;
    };
    //...

     继承可以有类式继承和原型式继承,本程序实现了这两种方法

    类式继承实现工厂方法的继承

    View Code
    /* 
     * 抽象类
     * 创建器,声明工厂方法 
     */
    var IFactory = function() {};
    /**
     * 1. 获取具体运算类实例,并检查是否实现了接口
     * 2. 用获取的实例调用同名运算方法
     * @param {Number} a
     * @param {Number} b
     * @return {Number}
     */
    IFactory.prototype.getResult = function(a, b) {
        var oper = this.factoryMethod();
        //判断实例是否实现了Operation接口中的所有方法
        Interface.ensureImplement(oper, Operation);
        return oper.getResult(a, b);
    };
    IFactory.prototype.factoryMethod = function() {
        throw new Error('IFactory是一个抽象类,子类需要实现factoryMethod方法');
    };
    /*
     * 加法工厂类
     * 具体的创建器,实现IFactory中的工厂方法,并返回具体的运算符对象
     */
    var AddFactory = function() {};
    //继承IFactory抽象类
    extend(AddFactory, IFactory);           
    AddFactory.prototype.factoryMethod = function() {
        return new OperationAdd;                //子类创建运算类实例
    };

     原型式继承实现搭建工厂方法

    //原型式继承使用的辅助函数
    var clone = function(object) {
        //检查object是不是字面量对象
        if(Object.prototype.toString.call(object) !== '[object Object]') {
            throw new Error('在clone函数中传递的不是字面量对象');
        }
        var F = function() {};
        F.prototype = object;
        return new F();
    };
    //模仿抽象类
    var iFactory = {
        getResult: function(a, b) {
            //获取运算类对象
            var oper = this.factoryMethod();
            //通过具体运算类,返回结果
            return oper.getResult(a, b);
        },
        factoryMethod: function() {
            throw new Error('子类需要实现factoryMethod方法');
        }
    };
    //原型式继承iFactory对象
    var subFactory = clone(iFactory);
    //覆盖iFactory中的方法
    subFactory.factoryMethod = function() {
        return new OperationSub();
    };

     现在已经把整个程序业务写好了,看看怎样使用我们刚才所创建的一大推东西

    //--------------------- test --
    (function() {
        try{
            //创建加法工厂实例
            var addFactory = new AddFactory();
            //用加法工厂创建出来的加法类实现两参数相加
            var result = addFactory.getResult(4, 3);
            console.log(result);
            //原型式继承的测试
            //console.log(subFactory.getResult(3, 1));      
        }
        catch(e) {
            console.log(e.message);        
        }
    })();

    客户端使用是不是很简单呢。 

    项目开发中遇到的问题:

    在辅助函数/对象中大量使用了throw new Error()语句,当错误发生时会允许你自定义错误提示信息。但这个提示却不能定位的那么完美。

  • 相关阅读:
    bootstrap-select.js 下拉框多选后动态赋值
    vs2012 未找到与约束 ContractName Microsoft.VisualStudio.Utilities.IContentTy...
    jquery 报错 Uncaught TypeError: Illegal invocation
    火狐浏览器的RestClient,接口测试,Post提交数据
    destoon二次开发 操作数据库可运行示例
    ZendStudio13 PHP调试环境快速配置
    VR发展的最大障碍在于内容?
    优秀博文链接
    LoopMatrix
    串口输出float型数据
  • 原文地址:https://www.cnblogs.com/mackxu/p/factorymehod2.html
Copyright © 2011-2022 走看看