javascript - نمط سينجلتون في العقيدات-هل هو مطلوب؟




node.js design-patterns singleton (9)

كل ما سبق هو مبالغة. هناك مدرسة فكرية تقول أن أنماط التصميم تظهر أوجه قصور في اللغة الفعلية.

لا تحتاج اللغات مع OOP المستند إلى النموذج الأولي (بدون فئات) إلى نمط مفرد على الإطلاق. يمكنك ببساطة إنشاء كائن واحد (طن) على الطاير ثم استخدامه.

بالنسبة للوحدات النمطية في العقدة ، نعم ، يتم تخزينها مؤقتًا بشكل افتراضي ، ولكن يمكن تعديلها على سبيل المثال إذا كنت تريد تحميل التغييرات في الوحدة.

ولكن نعم ، إذا كنت ترغب في استخدام الكائن المشترك في جميع أنحاء ، وضعه في وحدة نمطية الصادرات على ما يرام. فقط لا تعقيدها مع "نمط المفرد" ، لا حاجة لذلك في جافا سكريبت.

جئت مؤخرا عبر هذا المقال حول كيفية كتابة مفردة في Node.js. أنا أعلم أن وثائق require states ما states :

يتم تخزين الوحدات النمطية مؤقتًا بعد أول مرة يتم تحميلها. قد لا تتسبب مكالمات متعددة تتطلب ('foo') في تنفيذ تعليمات برمجية الوحدة النمطية عدة مرات.

لذا يبدو أن كل وحدة مطلوبة يمكن أن تستخدم بسهولة singleton بدون كود singlebreliler.

سؤال:

هل تقدم المقالة أعلاه جولة حول الحل لإنشاء مفردة؟


ابقائها بسيطة.

foo.js

function foo() {

  bar: {
    doSomething: function(arg, callback) {
      return callback('Echo ' + arg);
    };
  }

  return bar;
};

module.exports = foo();

ثم فقط

var foo = require(__dirname + 'foo');
foo.doSomething('Hello', function(result){ console.log(result); });

لا. عندما يخفق التخزين المؤقت لوحدة النمط في Node ، يفشل هذا النمط المفرد. لقد قمت بتعديل المثال للتشغيل بشكل مفيد على OSX:

var sg = require("./singleton.js");
var sg2 = require("./singleton.js");
sg.add(1, "test");
sg2.add(2, "test2");

console.log(sg.getSocketList(), sg2.getSocketList());

هذا يعطي النتيجة التي توقعها المؤلف:

{ '1': 'test', '2': 'test2' } { '1': 'test', '2': 'test2' }

لكن تعديل صغير يهزم التخزين المؤقت. على OSX ، افعل هذا:

var sg = require("./singleton.js");
var sg2 = require("./SINGLETON.js");
sg.add(1, "test");
sg2.add(2, "test2");

console.log(sg.getSocketList(), sg2.getSocketList());

أو على نظام التشغيل Linux:

% ln singleton.js singleton2.js

ثم قم بتغيير سطر sg2 إلى:

var sg2 = require("./singleton2.js");

وبام ، هزم المفرد:

{ '1': 'test' } { '2': 'test2' }

لا أعرف طريقة مقبولة للتغلب على هذا. إذا كنت تشعر حقًا بالحاجة إلى جعل شيء ما يشبه مفرداتك ولا بأس من تلويث مساحة الاسم العالمية (والمشكلات العديدة التي يمكن أن تنتج) ، يمكنك تغيير getInstance() المؤلف getInstance() الخطوط إلى:

singleton.getInstance = function(){
  if(global.singleton_instance === undefined)
    global.singleton_instance = new singleton();
  return global.singleton_instance;
}

module.exports = singleton.getInstance();

ومع ذلك ، لم أواجه مطلقًا أي موقف في نظام الإنتاج حيث كنت بحاجة إلى القيام بأي شيء من هذا القبيل. كما أنني لم أشعر أبدًا بالحاجة إلى استخدام نمط المفرد في جافا سكريبت.


لا تحتاج إلى أي شيء خاص للقيام بفرد واحد في js ، يمكن أن يكون الكود الموجود في المقالة كما يلي:

var socketList = {};

module.exports = {
      add: function() {

      },

      ...
};

خارج node.js (على سبيل المثال ، في js المستعرض) ، تحتاج إلى إضافة الدالة المجمع يدوياً (يتم تلقائياً في node.js):

var singleton = function() {
    var socketList = {};
    return {
        add: function() {},
        ...
    };
}();

النظر إلى أبعد من ذلك في وحدة التحكّم بالتخزين المؤقت لوحدة التخزين في المستندات Modules:

يتم تخزين الوحدات النمطية مؤقتًا استنادًا إلى اسم الملف الذي تم حله. نظرًا لأن الوحدات النمطية قد تحل إلى اسم ملف مختلف استنادًا إلى موقع وحدة الاتصال (التحميل من مجلدات node_modules) ، فإنها ليست ضمانًا يتطلب ('foo') دائمًا إرجاع نفس الكائن نفسه ، إذا كان سيعتمد على ملفات مختلفة .

لذا ، اعتمادًا على مكان تواجدك عند طلب وحدة نمطية ، من الممكن الحصول على نسخة مختلفة من الوحدة.

يبدو أن الوحدات النمطية مثل وحدات ليست حلاً بسيطًا لإنشاء مفردات.

تحرير: أو ربما هم. مثلmkoryak ، لا يمكنني الخروج بحالة حيث قد يتم حل ملف واحد إلى أسماء ملفات مختلفة (بدون استخدام symlinks). ولكن (كالتعليقات علىJohnnyHK) ، سيتم تحميل وتخزين نسخ متعددة من ملف في node_modules مختلفة بشكل منفصل.


هذا له علاقة أساسا مع التخزين المؤقت nodejs. واضح وبسيط.

https://nodejs.org/api/modules.html#modules_caching

(ت 6.3.1)

التخزين المؤقت

يتم تخزين الوحدات النمطية مؤقتًا بعد أول مرة يتم تحميلها. وهذا يعني (من بين أشياء أخرى) أن كل مكالمة تتطلب ('foo') سوف تحصل على نفس الكائن الذي تم إرجاعه بالضبط ، إذا تم حل المشكلة إلى نفس الملف.

قد لا تتسبب مكالمات متعددة تتطلب ('foo') في تنفيذ تعليمات برمجية الوحدة النمطية عدة مرات. هذه ميزة مهمة. مع ذلك ، يمكن إرجاع الكائنات "المنجزة جزئياً" ، مما يسمح بتحميل التبعيات متعدية حتى عندما تتسبب في دورات.

إذا كنت ترغب في أن تقوم الوحدة بتنفيذ التعليمات البرمجية عدة مرات ، قم بتصدير دالة ، واستدعاء هذه الوظيفة.

وحدة التخزين المؤقت تحذيرات

يتم تخزين الوحدات النمطية مؤقتًا استنادًا إلى اسم الملف الذي تم حله. نظرًا لأن الوحدات النمطية قد تحل إلى اسم ملف مختلف استنادًا إلى موقع وحدة الاتصال (التحميل من مجلدات node_modules) ، فإنها ليست ضمانًا يتطلب ('foo') دائمًا إرجاع نفس الكائن نفسه ، إذا كان سيعتمد على ملفات مختلفة .

بالإضافة إلى ذلك ، على أنظمة الملفات غير الحساسة لحالة الأحرف أو أنظمة التشغيل ، يمكن أن تشير أسماء الملفات التي تم حلها إلى نفس الملف ، ولكن ستظل ذاكرة التخزين المؤقت تتعامل معها كوحدات نمطية مختلفة وستقوم بإعادة تحميل الملف عدة مرات. على سبيل المثال ، تتطلب (". / foo") وتتطلب ('. / FOO)) إرجاع نوعين مختلفين ، بغض النظر عن ما إذا كان أو لم يكن .foo و ./FOO نفس الملف.

لذلك بعبارات بسيطة.

إذا كنت تريد سينجلتون. تصدير كائن .

إذا كنت لا تريد سينغلتون. تصدير وظيفة (والقيام بالأشياء / عودة الاشياء / أيا كان في تلك الوظيفة).


Singletons على ما يرام في JS ، فهي لا تحتاج إلى أن تكون مطول جدا.

في العقدة إذا كنت بحاجة إلى مفردة ، على سبيل المثال لاستخدام نفس مثيل ORM / DB عبر الملفات المختلفة في طبقة الخادم ، يمكنك حشو المرجع إلى متغير عام.

ما عليك سوى كتابة وحدة نمطية تنشئ الفهرس العام إذا لم تكن موجودة ، ثم ترجع مرجعًا إلى ذلك.

@ allen-luce كان صحيحًا مع مثال رمز الحاشية السفلية الذي تم نسخه هنا:

singleton.getInstance = function(){
  if(global.singleton_instance === undefined)
    global.singleton_instance = new singleton();
  return global.singleton_instance;
};

module.exports = singleton.getInstance();

ولكن من المهم ملاحظة أن استخدام الكلمة الرئيسية new غير مطلوب. أي شيء قديم ، وظيفة ، iife ، وما إلى ذلك ستعمل - لا يوجد الفودو OOP يحدث هنا.

نقاط المكافأة إذا قمت بإغلاق بعض العوامل داخل إحدى الوظائف التي ترجع مرجعًا إليها ، وجعل هذه الوظيفة عالمية ، فحتى إعادة تعيين المتغير الشامل لن يؤدي إلى حدوث المثيلات التي تم إنشاؤها من قبل - على الرغم من أن ذلك مفيد بشكل مفيد.


وحيدة في node.js (أو في متصفح JS ، لهذا الأمر) من هذا القبيل غير ضرورية تماما.

نظرًا لأن الوحدات النمطية يتم تخزينها مؤقتًا وتحميلها ، يمكن بسهولة إعادة كتابة المثال المقدم على الرابط الذي قدمته ببساطة:

var socketList = {};

exports.add = function (userId, socket) {
    if (!socketList[userId]) {
        socketList[userId] = socket;
    }
};

exports.remove = function (userId) {
    delete socketList[userId];
};

exports.getSocketList = function () {
    return socketList;
};
// or
// exports.socketList = socketList

جرب drex : https://github.com/yuryb/drex

يشاهد drex وحدة نمطية للتحديثات ويتطلب إعادة الوحدة بشكل صحيح بعد التحديث. رمز جديد يتطلب () د كما لو أن الكود الجديد هو وحدة مختلفة تماما ، لذلك require.cache ليست مشكلة.







javascript node.js design-patterns singleton