每天写500字

函数式版的Class

2019-11-20  本文已影响0人  业翔

我在写程序的时候,打算定义数据类型时,经常碰到一个疑惑,到底应该使用基本数据结构封装它,还是使用函数来封装它。

例如封装一个类型Student:

数据版本

function makeStudent(name, age)
{
   return {name: name, age: age};
}

function getName(student)
{
   return student.name;
}

function getAge(student)
{
   return student.age;
}

函数版本

function makeStudent(name, age)
{
    return function(method)
    {
        if (method == "getName") {
            return name;
        }
        else if (method == "getAge") {
            return age;
        }
    }
}

function getName(student) {
    return student("getName");
}

function getAge(student) {
    return student("getAge");
}

第一个小例子中,makeStudent使用一个Map来封装对象。第二个小例子中,使用函数来封装对象。
这两个小例子都能完成任务,且对于上层使用者来说是完全透明的。然而它们各自的优势,以及使用场景在哪里呢?

首先可以直观看到的是,而且数据版的student的内部数据是全部公开的,任何人都可以看到它的所有字段内容。

而且使用数据版的student有被修改的风险。例如以下程序:

let student = makeStudent("zhangsan", 20);
student.name = "lisi";

上面的例子中,原本student的名字是zhangsan,却可以被改名为lisi。

而使用函数版的student,却没有这些担忧。事实上,函数版的student更接近OOP中的class,因此能做到很多class能做到的事情。

比如我们可以实现多态。

如何理解呢?假设需要再定义一个Teacher类型。

function makeTeacher(name, sex)
{
    return function(method)
    {
        if (method == "getName") {
            return "teacher:" + name;
        }
        else if (method == "getSex") {
            return sex;
        }
    }
}

function getSex(teacher)
{
    return teacher("getSex");
}

这个例子中多态的特性主要表现在getName这个函数上:

let teacher = makeTeacher("老师A", 1);
let student = makeStudent("学生A", 20);

let name1 = getName(teacher);
let name2 = getName(student);

调用同样的函数,teacher和student的行为是不一样的。这或许就是函数式的多态吧。

而上面的各种make函数,其实就是函数式版本的class,但更加轻量,更加灵活。

上一篇 下一篇

猜你喜欢

热点阅读