【问题标题】:Splitting up a large class with modules用模块拆分一个大类
【发布时间】:2014-08-19 02:12:58
【问题描述】:

我正在尝试构建我的第一个(浏览器)库,并选择使用节点样式的 commonjs 模块 + browserify 来组织我的代码。我对它进行了结构化,因此每个模块都包含 1 个类,效果非常好,直到一些类开始变得令人眼花缭乱。

所以我假设我有一个像这样的课程

module.exports = MyClass;

function MyClass() {
  //initializing stuff

  this.publiceMethod= function publicMethod() {
    //do stuff
  };

  var privateMethod = function privateMethod() {
    //do stuff
  };
}

MyClass.prototype.notSureMethod = function notSureMethod() {
  //err... static method?
}

问题是我有大量的方法使用各种声明方法(this.methodvar methodthis.prototype.method)。我想知道是否有一种相对简单的方法来创建另一个模块并将它们作为类定义的一部分放入MyClass 以提高可读性。

我正在寻找的理想行为类似于一个模块,它是一个自执行函数,与调用它的对象共享相同的范围(如果可能,包括私有变量/方法)。

我现在才学习 JS 几个星期,所以如果我是白痴,请放轻松。在此先感谢:)

--编辑--

盲目地玩弄它,我已经弄清楚如何使用原型和公共方法来做我正在寻找的事情。

//Underneath MyClass definition
require('./prototype-methods')(MyClass);
require('./public-methods')(MyClass);

那么它在其他文件中的要点是:

module.exports = function(MyClass) {
  MyClass.prototype.method = . . . .

  MyClass.method = . . . .
}

所以这让我想知道是否有办法用私有方法做类似的事情。有什么想法吗?

---编辑2---

你的用例到底是什么?你能举个例子说明你的 上课呢?

我正在为网络音频 api 创建一个库,它基本上可以让您创作音乐。我有一个库的名称空间,并且名称空间(目前)包含几个不同的类。有score 类,它充当parteffectplayer 类之间的中介。 part 类只是 instrument 的包装器,instrument 是一个具有播放音乐功能的对象。

命名空间有一个工厂函数,它返回一个新的score 实例,而该实例又具有一个工厂函数,它返回新的part(s)、effect(s),最终返回player。此外,在任何给定时间都可能有超过 1 个分数,因此我可能会制作一个播放列表。

我最初尝试使用纯函数模式,但我的代码具有意大利面条的新含义。我对命名空间/类比对功能模式更熟悉。总的来说,我一直在像构建普通的 javascript 文件一样构建库,但由于增加了复杂性,我一直在使用 commonjs 模块 + browserify 轻松地将代码拆分为不同的文件/构建部分。

这个问题所涉及的具体类是part 类。我希望库在它接受的符号方面非常灵活,因此我需要添加很多方法来解释所有这些符号(= 大文件)。

【问题讨论】:

  • 大多数时候,如果你使用模块,你倾向于重构一些东西以避免使用构造函数,除非有必要(至少 这样做)。顺便说一句,它是多少行?
  • 目前大约有 550 行。我不确定这对其他人来说是大是小,但对我来说很难略过它。并感谢建议的编辑 - 这正是我的意思。

标签: javascript node.js browserify commonjs


【解决方案1】:

我发现通过将MyClass 作为参数传递给模块,我几乎可以使用模块将除私有成员之外的所有内容添加到MyClass

似乎我可以在技术上使用eval 添加/访问私有成员,但有人告诉我这是邪恶的。只需从文件中取出原型和公共方法就可以显着减少文件,因此将私有成员保留在其中是非常好的。

【讨论】:

    【解决方案2】:

    isbn 978-0-596-80675-0(第 5 章对象创建模式/沙盒模式), isbn 0-596-10199-6(第 10 章模块和命名空间/模块实用程序)

    目前,我也在寻找创建私有数据的便捷方法。我目前使用这样的继承功能模式和defineClass:

    var defineClass = function () {
        var inheritance = function inheritance() { };
        return function defineClass(data) {
            var classname = data.name,
                superclass = data.extend || Object,
                constructor = data.construct || function () { },
                methods = data.methods || {},
                statics = data.statics || {},
                borrows,
                provides;
            if (!data.borrows) {
                borrows = [];
            }
            else {
                if (data.borrows instanceof Array) {
                    borrows = data.borrows;
                }
                else {
                    borrows = [data.borrows];
                };
            };
            if (!data.provides) {
                provides = [];
            }
            else {
                if (data.provides instanceof Array) {
                    provides = data.provides;
                }
                else {
                    provides = [data.provides];
                };
            };
            inheritance.prototype = superclass.prototype;
            var proto = new inheritance();
            for (var i = 0; i < borrows.length; i++) {
                var c = borrows[i];
                for (var p in c.prototype) {
                    if (typeof c.prototype[p] != "function") continue;
                    proto[p] = c.prototype[p];
                }
            }
            for (var p in methods) {
                proto[p] = methods[p];
            };
            proto.constructor = constructor;
            constructor.superclass = superclass.prototype;
            if (classname) {
                proto.classname = classname;
            };
            for (var i = 0; i < provides.length; i++) {
                var c = provides[i];
                for (var p in c.prototype) {
                    if (typeof c.prototype[p] != "function") {
                        continue;
                    };
                    if (p == "constructor" || p == "superclass") {
                        continue;
                    };
                    if (p in proto && typeof proto[p] == "function" && proto[p].length == c.prototype[p].length) {
                        continue;
                    };
                    throw new Error("Class " + classname + " are not provided method " + c.classname + "." + p);
                };
            };
            constructor.prototype = proto;
            for (var p in statics) {
                constructor[p] = statics[p];
            };
            return constructor;
        }
    }();
    
    //SAMPLE CODE
    var tempObj = function () { };
    // example of a variable
    tempObj.prototype.distance = 0;
    // example of a method
    tempObj.prototype.walk = function (time) {
        this.distance = this.distance + time * this.walkSpeed
    };
    tempObj.prototype.toString = function () {
        return this.name + " distance " + this.distance
    };
    
    var Animal = defineClass({
        name: "Animal",
        construct: function (name, walkSpeed) {
            this.name = name;
            this.walkSpeed = walkSpeed;
        },
        borrows: tempObj,
        methods: {
            distance: tempObj.prototype.distance
        }
    });
    
    var tempObj2 = defineClass({
        methods: {
            fly: function (time) {
                this.distance = this.distance + time * this.flySpeed
            }
        }
    });
    
    var Bird = defineClass({
        name: "Bird",
        construct: function (name, walkSpeed, flySpeed) {
            // call the parent constructor
            Bird.superclass.constructor.call(this, name, walkSpeed)
            this.flySpeed = flySpeed
        },
        extend: Animal,
        borrows: tempObj2
    });
    
    var Cuckoo = defineClass({
        name: "Cuckoo",
        extend: Bird,
        construct: function (name, walkSpeed, flySpeed) {
            // call the parent constructor
            Cuckoo.superclass.constructor.call(this, name, walkSpeed, flySpeed)
            this.word = "cucoo";
        },
        methods: {
            say: function () {
                return this.name + " says " + this.word;
            }
        }
    });
    
    var animal = new Animal("Dog", 2);
    animal.walk(3);
    var dd = animal.toString();             // => Dog distance 6
    
    bird = new Bird("Bird", 1, 10);
    bird.walk(3);
    var ww = bird.toString();               // => Bird distance 3
    bird.fly(2);
    var ff = bird.toString();               // => Bird distance 23
    
    cuckoo = new Cuckoo("Cuckoo", 1, 10);
    cuckoo.walk(3);
    var ww = cuckoo.toString();             // => Cuckoo distance 3
    cuckoo.fly(2);
    var ff = cuckoo.toString();             // => Cuckoo distance 23
    var cSay = cuckoo.say();                // => Cuckoo says cucoo
    

    【讨论】:

      【解决方案3】:

      你的用例到底是什么?你能举例说明你的班级是做什么的吗?

      因为采用面向对象的方式并不总是在 JavaScript 中做事的最佳方式。节点样式的模块以及函数是 js 中的一等公民这一事实使得采用函数式方式变得非常容易。这意味着您可以导出只做一件事的单个函数。例如:

      module.exports = function(x, y) {
        return x * y
      }
      

      在第二个模块中,你可以像这样使用这个函数:

      var add = require('./add.js')
      var result = add(15, 23);
      

      如果您想了解更多信息,请查看this nodeschool workshop

      【讨论】:

      • 我更新了我的问题以澄清我的用例和类。
      猜你喜欢
      • 2020-07-02
      • 2021-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-24
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多