Node.jsのclass vs module

7093 ワード

Node.jsのclass vs module


classはオブジェクト向けプログラミングにおける重要な概念であり、誰もそれを突っ込むことができないほど強いが、本文はやはりNodeを対象にしたい.jsはclassとmoduleを比較し、実際の2人と結びつけて自分の考えを話します.

class


似たようなものの共通性を抽象化することによってclassが得られ、すべてのオブジェクト向けプログラミング言語の中で最も重要で最も有用な2つの特性は:継承と多態であり、この2つの特性がなければオブジェクトに向かって暗然として色を失うに違いない.著者の理解で継承と多態を簡単に紹介する.
  • 継承
  • 1つのclassは別のclassを継承して親classの属性と方法を備えることができ、これにより大量の重複コードの作成を減らすことができる.例えば、Animal classは動物が持つ属性と行為を抽象化することができ、猫科動物Cats calssはAnimal classを継承し、いくつかの猫科動物の属性と行為を定義することができ、さらに下のCat、Tiger、LeopardなどのclassはCats classを継承することができ、それらは自分だけの属性と行為だけを定義する.
    上記の例はオブジェクト継承の思想を体現しており、異なるレベルの抽象で重複コードの作成を減らすことで、プログラマはこれらの動物をシミュレートするための「動物世界」プログラムを容易に構築することができる.
  • マルチステート
  • 多態は継承から離れられない.オブジェクトタイプが同じだが行動表現が異なることを指す.Animalタイプの変数animalがあると仮定する.それは具体的な動物を表す.Animal calsでeat行動が定義されている場合、animalオブジェクトにもeat方法があるはずだ.そのため、プログラムはanimal.eat()を呼び出して動物が食べ物を食べる行為が発生することを示すことができるが、動物という抽象的なものはeatできず、Cat、Tiger、Leopardのような具体的な動物はeat行動を起こすことができるので、animal.eat()が具体的に何が起こるかはanimalがどの動物なのかにかかっています(実行時に知っています)
    同じタイプのオブジェクトは、同じメッセージに対して異なる動作(メソッド呼び出し)を生成します.これがマルチステートです.
    作者は対象に向かうプログラミング思想に関して、主に初期に《Think in Java》のこの本の中で学んだので、しかし仕事の中ですでに長い間OOの思惟でコードを書いていないで、継承と多態に対する理解が足りないかも知れなくて、だからもし間違いあるいは説明が適切でないならば大家に許してもらいます.
    JavaScriptでは、継承を使用するのは難しくありません.特にES 6以降のclass extendsの構文はclassを非常に迅速に継承することができますが、JavaScriptは動的タイプ言語なので、多態説はありません.

    module


    classと比較すると、moduleには厳密な定義はありませんが、ここではclassと比較するためにmoduleを定義することができます.「対外暴露属性と方法の閉鎖集合」です.この閉鎖集合はclassの一例と同等であることが多い(理解できませんが、確かにそうです).
    classの動物の例では、「動物世界」プログラムを構築するのではなく、「動物クエリー」システムを実現すると仮定し、Animal(動物)、Cats(猫科)、Cat(猫)概念は依然として存在するが、classで定義すべきではないか.もしそうなら、いつnewすればいいですか?
    上記の質問には良い答えはありません.この場合、考え方を変えて、moduleでシステムを組織することができます.catはモジュールとして、cat情報を内部的に定義し、外部アクセスのために標準インタフェースを提供します.ユーザーがcatの資料を検索したい場合、システムインタラクティブモジュールはcatモジュールの指定インタフェースを呼び出し、対応情報を返します.

    コードの例


    classとmoduleを記述する際,animalの例は想像に基づいているが,次に,著者らはこの例を補足して実際に貼り合わせようと試みたが,普段の作業は主にhttp serverに関連しているため,できるだけ少ないコードで動物クエリーシステムを実現し,classとmoduleでcatをそれぞれ実現し,その後比較した.

    server

    // server.js
    const http = require('http');
    const cat = require('./cat');
    
    const server = http.createServer(async (req, res) => {
        if (req.url === '/cat' && req.method === 'GET') {
            res.end(await cat.get());
            return;
        }
    
        res.end('404');
    });
    
    server.listen(3000);
    

    catのclassモード

    // cat.js 
    class Cat {
        constructor() {
            this.name = 'cat';
            this.description = 'a small domesticated carnivorous mammal with soft fur, a short snout, and retractile claws. It is widely kept as a pet or for catching mice, and many breeds have been developed.';
            this.author = 'shasharoman';
            this.updated = '2019-07-14';
        }
    
        async get() {
            return [
                `name: ${this.name}`,
                `description: ${this.description}`,
                `author: ${this.author}`,
                `updated: ${this.updated}`
            ].join('
    '); } async put() { // , cat } }; module.exports = new Cat();

    catのmoduleモード

    // cat.js
    let name = 'cat';
    let description = 'a small domesticated carnivorous mammal with soft fur, a short snout, and retractile claws. It is widely kept as a pet or for catching mice, and many breeds have been developed.';
    let author = 'shasharoman';
    let updated = '2019-07-14';
    
    exports.get = get;
    exports.put = put;
    
    async function get() {
        return [
            `name: ${name}`,
            `description: ${description}`,
            `author: ${author}`,
            `updated: ${updated}`
        ].join('
    '); } async function put() { // , cat }

    2つのモードを比較


    serverはGET /catのリクエストを受信してcatのフレーズに戻る情報を受信し、catはそれぞれclassとmoduleの2つの実現方式を採用しており、読者の皆さんは心の中で自分が合理的だと思っている方法を考えて選択し、続けていくことができます.
    ここで著者らの観点はmodule方式がclassより優れていると考えられ、以下の理由がある.
  • Node.js自体はモジュールに基づいて構築され、このようなシーンはモジュールの組織方式とNodeを用いる.jsプログラミング哲学はより一致し、統一されている.
  • ここではclass方式を用いてclassの利点(パッケージ、継承、多態など)を用いず、他のclassを継承したり、他のclassに継承されたりすることは不可能であり、システムはすべてこの方式で構築され、対象に向かって冗談のように見える.
  • thisポインタはこのようなシーンでは非常に曖昧であり、他の問題をもたらし、対象思想に向かうthisポインタは非常に重要であり、この方法ではthisは何の役割も果たしていない.
  • http serverシーンが複雑化した後,オブジェクト指向思想で行動抽象化を行い,JSでは難易度が高く,最終システムのほとんどのclassは上述したCatに類似しており,他のclassも継承されていない可能性がある.システムは対象思想で実現されているように見えるが、実際にはclassをmoduleの概念として使っているだけだ.

  • classにおけるthisの影響についてここでもう少し説明します.functionはJSの一等公民として非常に強力な役割を果たしていますが、thisに関わると複雑になりやすいです.functionの内部ではthisの指向に慎重に注目する必要があります.上記Catのようなclassには300行のコードが必要だと仮定します.
    class Demo {
        someMethod() {
            // 300 
            //  30 this 
        }
    }
    
    module.exports = new Demo();
    

    1つの方法300行のコードは明らかに可読性が悪いので、このとき私たちはそれを再構築するつもりで、この300行のコードの動作を5つのステップにまとめてみました.再構築されたコードは以下の通りです.
    class Demo {
        someMethod() {
            //  ,step1-5 , 
            //  someMethod , , BUG 
            _step1();
            _step2();
            _step3();
            _step4();
            _step5();
    
            function _step1() {
                //  50 
            }
    
            function _step2() {
                //  50 
            }
    
            // _step3 _step4 _step5  
        }
    }
    
    module.exports = new Demo();
    

    一見再構成されているように見えますが、ここで隠されている問題はthisポインタで、再構成前の300行のコードはthisを直接使用し、new Demo()という例を指し、再構成後のstep 1-5のthisはそれぞれのfunctionの呼び出し者globalを指しています(ただし、上記の世代コードではundefiend,why?)このようなthisの問題は避けられず、Jserは一般的にselfまたはthatを使用してthisの参照を外層に保持します.
    注目すべきでないthis問題が他の関連問題を引き起こすため、これだけで著者がclass組織moduleを使用する方法を排斥するのに十分であり、ましてや他にもいくつかの点がある.Javaではclassなしでプログラミングしないが、JSではそうではないので、著者はNodeを使うかどうかを判断するために多くの思考が必要だと考えている.jsオリジナルのモジュール組織方式か、define class方式か.

    Node.jsでclassを使用するシーン


    前文ではclassを使用しないことを強調してきましたが、moduleを使用して目的のシーンを達成するにはclassを使用する必要はありません.一部のシーンではclass方式を使用してコードを記述するのが合理的かもしれませんが、具体的には、著者が以下の点から考えることができると考えています.
  • 実現する必要があるものはnewされるシーンがありますか?newされる可能性のある回数?

  • 通常、1つのclassが定義され、最終的な目的はnewによって使用されることであり、様々な異なるシーンnewによって使用される必要がある.1つのclassがnewの1つのインスタンスのみが使用される(単例モード)、または1つのclass内部がstaticメソッドである場合、Nodeのためmodule方式を選択することを考慮すべきである.jsにおけるmoduleは天然の単例である
  • classを使用する場合、定義されたclassはextendsの他のclassがありますか?他のclassに継承される可能性はありますか?

  • この2つの点が単一のパターンを満たしていない場合は、99%がclassではなくmoduleを選択する必要があります.
  • moduleを使用する場合、定義されたmoduleにはステータスフィーチャーがありますか?異なるシーンでmoduleを異なる状態にしますか?

  • 開発者がRedisを操作するツールを実装する必要があると仮定し、Redis操作には必ずredis-server関連情報(host、port、db、passwordなど)が必要であると仮定すると、このツールはステータスがあり、ツール使用者は異なるredis-serverに接続する必要がある可能性があるので、ここではclassを使用することを選択する必要があります.
    上記のRedisツールがclass方式で実現されたと仮定すると,小型プロジェクトに1つの固定DBのみを適用し接続することを望むが,このmoduleは状態はあるが状態は固定であるためmodule方式を採用することができる.
  • システムは本当にすべての対象を必要としますか?すべて偽のオブジェクトですか?システム全体の動作はモジュールインタラクションとオブジェクトインタラクションのどちらに似ていますか?

  • functionは一等公民のJavaScriptとして,著者らはすべてオブジェクト向けにコードを記述する必要はないと考え,必要であればJavaなど他の言語を考慮すべきである.

    まとめ


    この文章を書いたのは最近ノードにいたからだ.jsプロジェクトでは「classを使うためにclassを使う」という現象が発見され、著者の心の中ではうるさいので、実際のプロジェクトでこのような現象に遭遇した場合、moduleではなくclassなのかを考えてほしい.
    ブログ