没有if-else块的JavaScript Factory模式

时间:2014-02-10 17:56:57

标签: javascript design-patterns factory factory-pattern

我想知道是否有更好的方法来实现createEmployee(),它使用字典或其他方式快速查找所请求的类型而不是if-else块。

function Clerk( options ) {
            this.hourRate = options.hourRate || 20;
            this.firstName = options.firstName || "no first name";
            this.lastName = options.lastName || "no last name";
            this.id = options.id || "-9999999999";
        }

        function Manager( options) {
            this.hourRate = options.hourRate || 200;
            this.firstName = options.firstName || "no first name";
            this.lastName = options.lastName || "no last name";
            this.id = options.id || "-9999999999";
            this.yearBonus = options.yearBonus || "200000";
        }

        function Teacher( options) {
            this.hourRate = options.hourRate || 100;
            this.firstName = options.firstName || "no first name";
            this.lastName = options.lastName || "no last name";
            this.id = options.id || "-9999999999";
            this.subject = options.subject || "history";
        }

        var EmployeesFactory = function() {};

        EmployeesFactory.prototype.createEmployee = function (options) {
            if(options.employeeType == "Clerk")
                employeeConstructor = Clerk;
            else if(options.employeeType == "Manager")
                employeeConstructor = Manager;
            else if(options.employeeType == "Teacher")
                employeeConstructor = Teacher;
            return new employeeConstructor(options);
        }

        var factory = new EmployeesFactory();
        var person = factory.createEmployee( {
            employeeType: "Manager",
            firstName: "Haim",
            lastName: "Michael",
            id: 234234234 } );

        document.write(person instanceof Manager);

3 个答案:

答案 0 :(得分:6)

试试这个:

var constructors;

constructors = {
    "Clerk" : function (options) {
        // your constructor code here for clerks
    },
    "Manager" : function (options) {
        // your constructor code here for managers
    },
    "Teacher" : function (options) {
        // your constructor code here for teachers
    }
};

EmployeesFactory.prototype.createEmployee = function (options) {
    return constructors[options.employeeType](options);
};

我建议将constructors对象隐藏在EmployeesFactory内。 这样你也可以摆脱不受欢迎的函数名称(ClerkManagerTeacher)。

此外,您应该只创建一次constructors对象并在create中重用它。不要在创建中实例化它。您可以通过以下方式执行此操作:

var EmployeesFactory = function () {
    var constructors;

    constructors = {
        "Clerk" : function (options) {
            // your constructor code here for clerks
        },
        "Manager" : function (options) {
            // your constructor code here for managers
        },
        "Teacher" : function (options) {
            // your constructor code here for teachers
        }
    };

    return {
        "create" : function (options) {
            return constructors[options.employeeType](options);
        }
    };
};

你这样得到工厂:

factory = EmployeesFactory();

并且可以通过这种方式创建:

factory.create(options);

所有这些都将是舒适的,隐藏在外部封闭的封闭内部,没有任何胆量悬挂在外面。

工厂模式的目的是隐藏对象构造的复杂性和细节,因此在某个方面缺少用于消费的方法 (我承认,小/最小的模式。通过使用闭包,你也可以获得隐藏的好处。

答案 1 :(得分:2)

是的,如你所说,使用字典:

function createEmployee(options) {
    return new {
        "Clerk": Clerk,
        "Manager": Manager,
        "Teacher": Teacher
    }[options.employeeType](options);
}

可能使对象文字成为静态变量constructors,并重新引入中间employeeConstructor变量以获得更多详细程度和更少混淆的语法: - )


不过,你的构造函数中有很多代码重复。你可以做得更干:

function Employee(options, defaultRate) {
    this.hourRate = options.hourRate || defaultRate;
    this.firstName = options.firstName || "no first name";
    this.lastName = options.lastName || "no last name";
    this.id = options.id || "-9999999999";
}

function Clerk(options) {
    Employee.call(this, options, 20);
}
function Manager(options) {
    Employee.call(this, options, 200);
    this.yearBonus = options.yearBonus || "200000";
}
function Teacher(options) {
    Employee.call(this, options, 100);
    this.subject = options.subject || "history";
}

答案 2 :(得分:0)

是的,下面的代码更清晰。

// Create this one time
var constructors = {};

constructors["Manager"] = Manager
constructors["Teacher"] = Teacher
...

// Each object
return new constructors[options.employeeType](options);