jjzjj

javascript - 如何为 JavaScript 选择 OO 设计模式

coder 2025-01-08 原文

我所说的 OO 是指经典的 OO。我一直在定义我的“类”(javascript 没有传统类)之间来回切换,使用模块模式提供隐私和使用对象字面量创建“公共(public)静态”集合。

当我创建“类”时,我没有指导力来确定要使用的组织类型。好吧,除了我的代码在没有设置任何选项的情况下同时通过了 jshint 和 jslint。

我正在处理大约 1500 行代码,因此在代码变得无法管理并且我不得不废弃它之前我需要一个“指导力量”。

我很清楚在 JavaScript 中编写“类”的不同方式。由 Alex MacCaw 编写的 JavaScript Web 应用程序教授的内容以及此处列出的多种方法。

但是,在应用程序方面,我只是不知道该使用什么方法。

最简单的似乎是对象字面量中的方法和变量的集合,如下所示:

var public_statics = {
    public_func: function () {},
    public_var: "hello"
}

最复杂的似乎是 - IIFE。

(function(){
    var private_var;
    function private_func(){
    }
})();

我如何知道使用哪一个或众多中间变体?

举个具体的例子:MVC 中的 Controller 怎么样。

目前(和一些随机选择的),我实现了这样一个 Controller :

var Co = {};
Co.Controller = function(){
    // 'classes' from Mo are called here
    // 'classes' from Su are called here
}

然后我将其他与控制相关的方法添加到 Co.

如何选择要使用的 OO 风格?


已更新

我的库目前分为 4 个命名空间:

var Mo = {},
    Vi = {},
    Co = {},
    Su = {};

模型、 View 和 Controller 应该是不言自明的,并且 (Su)pport 适用于所有未包含在 MVC 中的“类”,例如 DOM 访问、效果、调试代码等。

我应该使用什么 OO 风格来进一步组织这个库/代码?

Controller “类”示例:

/**
 **  Controller
 */

Co.Controller = function (o_p) {
    var o_p_string_send;
    Su.time();
    o_p = Mo[o_p.model].pre(o_p);
    if (o_p.result !== 'complete') {
        o_p_string_send = JSON.stringify(o_p);
        Su.time();
        //Su.log(o_p_string_send);
        Co.serverCall('pipe=' + o_p_string_send, function (o_p_string_receive) {
            Su.time();
            //Su.log(o_p_string_receive);
            o_p.server = JSON.parse(o_p_string_receive);
            Mo[o_p.model].post(o_p);
            Su.time(true);
            Su.log('Server time: [' + o_p.server.time + ']');
        });
    }
};

最佳答案

IFFE 经常让人难以阅读,就我个人而言,我不知道为什么它们会变得如此主流。我认为代码应该易于阅读和简洁。尝试模拟不属于语言规范的语言行为通常是一个非常愚蠢的想法。

例如,JavaScript 不支持多重继承、多态性或许多其他有趣的范例。所以很多时候,我们看到人们试图在 JS 中创建这些具有多态性或私有(private)成员等的疯狂方式。我认为这是一个错误。

我目前作为一种业余爱好项目在高性能 JS 数据结构库上工作(我试图超越 Google 的闭包和其他一些)。来自 C++ 和 Java 背景,我总是喜欢制作东西类,我喜欢继承等等。让我与您分享一些代码片段。起初,我以为我很聪明,因为我写的是这样的东西:

function __namespace(n, v) {
    return {"meta":{"namespace":n,"version":v}};
}

var FJSL = FJSL == undefined ? new __namespace("Fast JavaScript Library", 0.1) : FJSL;

__using = function(parent, child) {
    clazz = new child();
    clazz.super = new parent();
    if (clazz.super == undefined) return clazz;
    for (a in clazz.super) {
        for (b in clazz) {
            if (a == "constructor" || b == "constructor") continue;
            if (clazz[b] === clazz.super[a]) continue;
            if (a == b && typeof clazz[b] != typeof clazz.super[a]) throw "Typesafety breached on '" + a + "' while trying to resolve polymorphic properties."; 
            if (a == b && typeof clazz[b] == typeof clazz.super[a]) {
                clazz["_"+a] = clazz.super[a];
            } else if (clazz[a] == undefined) {
                clazz[a] = clazz.super[a];
            }
        }
    }
    return clazz;
};

我是这样使用它的(在一个简单队列的例子中):

FJSL.Array = function() { 
    this.data = [];

    this.contains = function(idx, element) {
        for (var i = idx; i < this.data.length; i++) {
            if (this.data[i] === element)
                return i;
        }
        return -1;
    }

    this.size = function() {
        return this.data.length;
    }
}

FJSL.Queue = function() {
    return __using(FJSL.Array, 
    function() {
        this.head = 0;
        this.tail = 0;

        this.enqueue = function(element) {
            this.data[this.tail++] = element;
        };

        this.dequeue = function() {
            if (this.tail == this.head)
                return undefined;
            return this.data[this.head++];
        };

        this.peek = function() {
            return this.data[this.head];
        };

        this.size = function() {
            return this.tail - this.head;
        };

        this.contains = function(element) {
            return this._contains(this.head, element);
        };
    }
)};

您会注意到我是如何伪装继承的(一个队列使用一个数组,哈哈,我很聪明)。然而,这对于a) 阅读b) 理解 来说绝对是疯狂的。我忍不住想起了这个模因:

让我向您展示功能等效的代码,而无需尝试进行所有这些花哨的预处理和后处理:

FJSL.Queue = function(opts) {
    this.options = opts;
    this.head = 0;
    this.tail = 0;
    this.data = [];
};

FJSL.Queue.prototype = {
    add : function(element) {
        this.data[this.tail++] = element;
    },

    enqueue : function(element) {
        this.data[this.tail++] = element;
    },

    dequeue : function() {
        if (this.tail == this.head) {
            return undefined;
        }
        return this.data[this.head++];
    },

    peek : function() {
        return this.data[this.head];
    },

    size : function() {
        return this.tail - this.head;
    },

    contains : function(element) {
        // XXX: for some reason a for : loop doesn't get JIT'ed in Chrome
        for (var i = this.head; i < this.data.length; i++) {
            if (this.data[i] === element) {
                return true;
            }
        }
        return false;
    },

    isEmpty : function() {
        if (size) {
            return true;
        }
        return false
    }, 

    clear : function() {
        this.data = [];
    }
};

显然,我必须为可能使用数组的任何其他结构复制原型(prototype)构造函数,但我想要完成的事情要清楚得多,即使是新手 JS 程序员也能分辨出发生了什么。不仅如此,如果人们想要修改代码,他们会确切地知道去哪里和做什么。

我的建议是不要陷入试图让 JS 表现得像 C++ 或 Java 的疯狂。它永远不会。是的,你可以伪造继承和私有(private)/公共(public)/ protected 成员,但 JS 从来没有打算这样做。我认为拥有这种臃肿的代码(试图模拟非标准行为)的后果是对高性能网络应用程序及其同类应用程序造成了很大的负担。

简而言之,我建议使用对象字面量:

var public_statics = {
    public_func: function () {},
    public_var: "hello"
}

易于理解、易于修改、易于扩展。如果您的系统非常脆弱,如果有人不小心更改了某些“私有(private)”变量,可能会崩溃和烧毁,那么您只需要对其进行记录即可。

关于javascript - 如何为 JavaScript 选择 OO 设计模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12078812/

有关javascript - 如何为 JavaScript 选择 OO 设计模式的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 如何为 emacs 安装 ruby​​-mode - 2

    我刚刚为fedora安装了emacs。我想用emacs编写ruby。为ruby​​提供代码提示、代码完成类型功能所需的工具、扩展是什么? 最佳答案 ruby-mode已经包含在Emacs23之后的版本中。不过,它也可以通过ELPA获得。您可能感兴趣的其他一些事情是集成RVM、feature-mode(Cucumber)、rspec-mode、ruby-electric、inf-ruby、rinari(用于Rails)等。这是我当前用于Ruby开发的Emacs配置:https://github.com/citizen428/emacs

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  6. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  7. ruby - Rails 3 的 RGB 颜色选择器 - 2

    状态:我正在构建一个应用程序,其中需要一个可供用户选择颜色的字段,该字段将包含RGB颜色代码字符串。我已经测试了一个看起来很漂亮但效果不佳的。它是“挑剔的颜色”,并托管在此存储库中:https://github.com/Astorsoft/picky-color.在这里我打开一个关于它的一些问题的问题。问题:请建议我在Rails3应用程序中使用一些颜色选择器。 最佳答案 也许页面上的列表jQueryUIDevelopment:ColorPicker为您提供开箱即用的产品。原因是jQuery现在包含在Rails3应用程序中,因此使用基

  8. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  9. 计算机毕业设计ssm+vue基本微信小程序的小学生兴趣延时班预约小程序 - 2

    项目介绍随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱小学生兴趣延时班预约小程序的设计与开发被用户普遍使用,为方便用户能够可以随时进行小学生兴趣延时班预约小程序的设计与开发的数据信息管理,特开发了小程序的设计与开发的管理系统。小学生兴趣延时班预约小程序的设计与开发的开发利用现有的成熟技术参考,以源代码为模板,分析功能调整与小学生兴趣延时班预约小程序的设计与开发的实际需求相结合,讨论了小学生兴趣延时班预约小程序的设计与开发的使用。开发环境开发说明:前端使用微信微信小程序开发工具:后端使用ssm:VU

  10. ruby-on-rails - environment.rb 中设置的常量在开发模式中消失 - 2

    了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl

随机推荐