مرجع
آخر الزيارات

خلط Mixin

2٬512 كلمة•0 مشاهدة•🗒️ منذ يوم
باختصار: في لغات البرمجة كائنية التوجه، Mixin (أو mixin) هو صنف (حوسبة) class، الذي يحتوي على طرق (methods) لاستخدامها من قبل أصناف (classes) أخرى دون أن تكون الصنف الأصل (parent class) من تلك الفئات الأخرى. في هذه المقالة 40 قسماً: «بلغات أخرى»، «في سويفت Swift» و«const extend = (obj, mixin) => {» وغيرها.
المحتويات
  1. بلغات أخرى
  2. في سويفت Swift
  3. const extend = (obj, mixin) => {
  4. end
  5. في روبي
  6. SystemVerilog
  7. class Student
  8. end
  9. الواجهات والسمات
  10. OCaml
  11. مزايا
  12. Cobra
  13. التاريخ
  14. في JavaScript
  15. لغات البرمجة التي تستخدم mixins
  16. تعريف
  17. func error(message:String) {
  18. في سكالا
  19. toString {
  20. last = function {
  21. بايثون
  22. });
  23. const first = function {
  24. EnumerableFirstLast.call(Array.prototype);
  25. في Common Lisp
  26. سكالا
  27. attr_accessor :name, :score
  28. // Implementation
  29. };
  30. Object.assign(obj1, mix1, mix2);
  31. في بيثون
  32. }
  33. تطبيقات
  34. end
  35. class Actor extends Person with Singer
  36. console.log(sam.fullName); // Samwise Gamgee
  37. };
  38. رائع
  39. func onError {
  40. Mixins في ActionScript

بدايةً، في لغات البرمجة كائنية التوجه، Mixin (أو mixin) هو صنف (حوسبة) class، الذي يحتوي على طرق (methods) لاستخدامها من قبل أصناف (classes) أخرى دون أن تكون الصنف الأصل (parent class) من تلك الفئات الأخرى. تعتمد كيفية وصول تلك الفصول الأخرى إلى أساليب mixin على اللغة. يوصف mixin في بعض الأحيان بأنه «مدرج» "included" بدلاً من «موروث» "inherited". ونتناول فيما يلي مزيدًا من التفاصيل.

من جانب آخر، يشجع Mixins على إعادة استخدام الكود، ويمكن استخدامه لتجنب غموض الميراث الذي يمكن أن يسببه الميراث المتعدد مشكلة الماس(diamond problem)، أو للتغلب على عدم دعم الميراث المتعدد في اللغة. يمكن كذلك اعتبار المزيج كواجهة (interface) مع الطرق المنفذة methods. هذا النمط (pattern) هو مثال لفرض مبدأ انعكاس التبعية (dependency inversion principle).

بلغات أخرى

من جانب آخر، في لغة محتوى الويب Curl، يتم استخدام الوراثة المتعددة كاصناف classes مع عدم وجود كائنات قد تنفذ طرقًاmethods. وتشمل mixins المشتركة عن سكينبل ControlUI الصورة وراثة من SkinnableControlUI، وكائنات واجهة المستعمل المفوضuser interface delegate التي تتطلب القوائم المنسدلة dropdown menus وراثة من StandardBaseDropdownUI classوهذا اسمه صراحة خلطmixin كما FontGraphicMixin، FontVisualMixin و NumericAxisMixin-of الاصناف classes. أضاف الإصدار 7.0 إمكانية الوصول إلى المكتبة بحيث لا يحتاج المزيج إلى أن يكون في نفس الحزمة أو أن يكون مجرد ملخص عام. يُعد مُنشئو التمويجات المصانع التي تسهل استخدام الوراثة المتعددة multiple-inheritanceدون التصريح الصريح interfaces or mixinsبالواجهات أو الخلطات.

في سويفت Swift

  • func error(message:String)
  • }
  • extension ErrorDisplayable {

ومن جهة أخرى، يمكن تحقيق Mixin في Swift باستخدام ميزة لغة تسمى التنفيذ الافتراضي في ملحق البروتوكولProtocol Extension. protocol ErrorDisplayable {

const extend = (obj, mixin) => {

  • Object.keys(mixin).forEach(key => obj[key] = mixin[key]);
  • return obj;
  • };
  • const sam = new Halfling('Sam', 'Loawry');
  • const frodo = new Halfling('Freeda', 'Baggs');
  • // Mixin the other methods
  • extend(Halfling.prototype, mixin);
  • console.log(sam.fullName); // Sam Loawry
  • console.log(frodo.fullName); // Freeda Baggs
  • sam.rename('Samwise', 'Gamgee');
  • frodo.rename('Frodo', 'Baggins');

end

  • s1 = Student.new("Peter", 100)
  • s2 = Student.new("Jason", 90)
  • s1 > s2 #true
  • s1 <= s2 #false

في روبي

مثال:

من جانب آخر، يعتمد أغلب عالم روبي على مزيج من خلال Modules. يتم تطبيق مفهوم mixins في Ruby من خلال include الكلمة الرئيسية التي نمرر عليها اسم الوحدة كمعلمة.

SystemVerilog

أمثلة

وفي هذا الصدد، يمكن للغات الأخرى التي لا تدعم mixins دعمها بطريقة مستديرة عبر تركيبات لغة أخرى. C # وVisual Basic. يدعم NET إضافة طرق التمديد على الواجهات، مما يعني أن أي فئة تطبق واجهة مع طرق التمديد المحددة سيكون لها طرق التمديد المتاحة كأعضاء زائفين.

TypeScript (وثائق mixins)

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

class Student

من جهة ثانية، include Comparable # The class Student inherits the Comparable module using the 'include' keyword

end

من جهة ثانية، # Here's the good bit - I get access to <, <=, >,>= and other methods of the Comparable Interface for free.

الواجهات والسمات

ومن جهة أخرى، يمكن للواجهاتInterfaces المدمجة مع البرمجة الموجهة إلى الجوانب أن تنتج كذلك مزيجًا متكاملًا باللغات التي تدعم هذه الميزات، مثل C # أو Java. علاوةً على ذلك، من خلال استخدام نمط واجهة العلامة والبرمجة العامة marker interface pattern, generic programming, وطرق التمديدextension methods، فإن C # 3.0 لديه القدرة على محاكاة الخلطات. مع الإصدار 3.0 من C #، تم تقديم طرق التمديدExtension Methods [2] ويمكن تطبيقها، ليس فقط على الاصناف classes ولكن كذلك على الواجهاتclasses. توفر طرق التمديدExtension Methods وظائف إضافية في فصل دراسي موجود بدون تعديل الصنف. ثم يصبح من الممكن إنشاء فئة مساعد ثابتة static helper classلوظائف محددة تحدد طرق التمديدextension methods. نظرًا لأن الاصناف تطبق الواجهة (حتى إذا لم تحتوي الواجهة الفعلية على أي طرق أو خصائص لتطبيقها)، فستلتقط جميع طرق الامتداد كذلك.

ومن جهة أخرى، لا يحتاج ECMAScript (في أغلب الحالات التي يتم تنفيذها كجافا سكريبت) إلى محاكاة تكوين الكائن عن طريق نسخ الحقول تدريجيًا من كائن إلى آخر. وهو يدعم في الأساس خاصية Trait و mixin تعتمد على تكوين العناصر عبر الكائنات الوظيفية التي تنفذ سلوكًا إضافيًا ثم يتم تفويضها عبر call أو apply على الكائنات التي تحتاج إلى مثل هذه الوظائف الجديدة.

من جانب آخر، تقدم Java 8 ميزة جديدة في شكل طرق افتراضية للواجهاتdefault methods for interfaces. بشكل أساسي، يسمح بتعريف طريقة method في واجهة interface مع تطبيق في السيناريو عند إضافة طريقة طريقةmethod جديدة إلى واجهة interface بعد الانتهاء من إعداد برمجة صنف الواجهة interface class. إن إضافة وظيفة جديدة إلى الواجهة تعني تنفيذ الطريقة method في كل صنف class تستعمل الواجهة interface. تساعد الطرق الافتراضية Default methods في هذه الحالة حيث يمكن تقديمها إلى واجهة interface في أي وقت ولها بنية منفذة يتم استخدامها لاحقًا من قبل الاصناف المرتبطة associated classes. ومن ثم تضيف الطرق الافتراضية default methodsإمكانية لتطبيق المفهوم بطريقة من النوع المختلطmixin.

OCaml

  • Perl (من خلال الأدوار في امتداد Moose لنظام كائن Perl 5)
  • سمات " PHP "
  • Magik

مزايا

وفي السياق ذاته، يسمح Mixins بالوراثة واستخدام الميزات المطلوبة فقط من الفئة الرئيسية، وليس بالضرورة جميع الميزات من الفئة الرئيسية.

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

كذلك، إنه يوفر آلية للميراث المتعدد من خلال السماح لفئات متعددة باستخدام الوظيفة المشتركة، ولكن بدون الدلالات المعقدة للوراثة المتعددة.

Cobra

وعلى صعيد آخر، D (يسمى "mixins template" ؛ يتضمن D كذلك عبارة "mixin" التي تجمع السلاسل ككود.)

سهم Dart

من جانب آخر، ColdFusion (يعتمد على الفئة باستخدام ويشمل والكائن عن طريق تعيين الأساليب من كائن إلى آخر في وقت التشغيل)

Factor

Curl (مع Curl RTE)

التاريخ

إضافةً إلى ذلك، ظهر Mixins لأول مرة في نظام Flavors الموجه للكائنات في Symbolics - تم تطويره بواسطة Howard Cannon-، والذي كان نهجًا في اتجاه الكائن المستعمل في Lisp Machine Lisp. الاسم مستوحى من صالون Steve's Ice Cream Parlour في Somerville، ماساتشوستس: قدم صاحب متجر الآيس كريم نكهة أساسية من الآيس كريم (الفانيليا والشوكولاتة، وما إلى ذلك) وتم خلطه مع مزيج من العناصر الإضافية (المكسرات، الكوكيز، حلوى، وما إلى ذلك) ويسمى هذا البند على «مزيج»"mix-in"، له عبارة علامة تجارية خاصة في ذلك الوقت.

في JavaScript

  • يتم استخدام دالة التمديدextend function لخلط السلوك في: 'use strict';
  • const Halfling = function (fName, lName) {
  • this.firstName = fName;
  • this.lastName = lName;
  • };
  • const mixin = {
  • fullName {
  • return this.firstName + ' ' + this.lastName;
  • },
  • rename(first, last) {
  • this.firstName = first;
  • this.lastName = last;
  • return this;
  • }
  • };
  • // An extend function

وفي السياق ذاته، عدم مشاركة السلوك المشترك. تقوم Metaobjects بحل هذه المشكلة عن طريق فصل خصائص المجال domain المحددة للكائنات عن خصائصها الخاصة بسلوكها.

إضافةً إلى ذلك، يخلط خصائص مجال النموذجmodel domain مع مجال التطبيقimplementation domain.

ومن جهة أخرى، الكائن الحرفي extend النهج – The Object-Literal and extend Approach

وعلى صعيد آخر، من الممكن تقنيًا إضافة سلوك إلى كائن من خلال ربطbinding الوظائف بالمفاتيح الموجودة في الكائنobject. ومع ذلك، فإن عدم الفصل بين الحالة والسلوك له عيوب:

لغات البرمجة التي تستخدم mixins

وفي هذا السياق، بخلاف Flavours و CLOS (جزء من Common Lisp)، بعض اللغات التي تستعمل mixins هي:

في هذا الإطار، Ada (من خلال توسيع سجل موجود بعلامات مع عمليات عشوائية في عام)

تعريف

ومن جهة أخرى، Mixins هي مفهوم لغوي يسمح للمبرمج بحقن بعض التعليمات البرمجية في صنف (حوسبة) class. برمجة Mixin هي نمط من تطوير البرمجيات حيث يتم إنشاء وحدات الوظائف في class صنف ثم يتم مزجها مع class اصناف أخرى.

وعلى صعيد آخر، يعمل class صنف mixin كفئة رئيسية، وتحتوي على الوظيفة المطلوبة. يمكن supclass لصنف فرعي أن ترث أو تعيد استخدام هذه الوظيفة، ولكن ليس كوسيلة للتخصص. عادةً، يقوم المزيج بتصدير الوظيفة المطلوبة إلى child class صنف فرعي، دون إنشاء علاقة مفردة جامدة «هل هي»"is a". هنا يكمن الاختلاف المهم بين مفاهيم الخلط والميراث، في أنه لا يزال بإمكان الصنف الفرعي أن يرث جميع ميزات الصنف الاصل parent class، ولكن، الدلالات عن الفرع «كونه نوعًا»"being a kind of" من الاصل parent لا تحتاج بالضرورة إلى تطبيقها.

func error(message:String) {

  • // Do what it needs to show an error
  • //...
  • print(message)
  • }
  • }
  • struct NetworkManager : ErrorDisplayable {

في سكالا

def sing { println(" singing … ") }

//more methods

إضافةً إلى ذلك، سكالا لديها نظام غني من النوع والسماتtype system and Traits جزء منه مما يساعد على تنفيذ سلوك الخلطmixin. كما يظهر اسمها، يتم استخدام Traits السمات عادة لتمثيل ميزة أو سمة مميزة عادة ما تكون متعامدة مع مسؤولية نوع ملموس أو على الأقل في حالة معينة. مثلًا، تم تصميم القدرة على الغناء على أنها سمة متعامدة: يمكن تطبيقها على الطيور والأشخاص وما إلى ذلك. trait Singer{

toString {

  • return `${this.name} was born in ${this.city} in ${this.born}`;
  • },
  • age {
  • const year = new Date.getFullYear;
  • const born = new Date(this.born).getFullYear;
  • return year - born;
  • }
  • };
  • // Mixin 2
  • const mix2 = {
  • toString {
  • return `${this.name} - ${this.city} - ${this.born}`;
  • }

last = function {

return this[this.length - 1]؛

بايثون

  • Racket(وثائق ميكسين)
  • Raku
  • روبي

});

// Application - explicit delegation:

وفي هذا السياق، // applying [first] and [last] enumerable behavior onto [Array]'s [prototype].

const first = function {

return this[0]؛

},

EnumerableFirstLast.call(Array.prototype);

  • // Now you can do:
  • const a = [1, 2, 3]؛
  • a.first; // 1
  • a.last; // 3

في Common Lisp

كذلك، 80 يمكننا كذلك حساب عرض bordered-button. استدعاء object-width يحسب 84. والنتيجة هي مجموع نتائج الطريقتين الساريتين: object-width الأسلوب button الفئة وعرض object-width الأسلوب border-mixin الفئة. 84 ? (object-width (make-instance 'bordered-button))

وفي السياق ذاته، ((text :initform "click me"))) هناك طريقة لكائنات زر الفئة التي تحسب العرض بناءً على طول نص الزر. + هو مؤهل الطريقة لمجموعة الطريقة التي تحمل نفس الاسم. (defmethod object-width + ((object button))

وعلى صعيد آخر، هناك طريقة لحساب عرض الحدود. هنا فقط 4. (defmethod object-width + ((object border-mixin))

4)

إضافةً إلى ذلك، object-width هو دالة عامة مع وسيطة واحدة تستعمل تركيبة طريقة +. تحدد هذه التركيبة أنه سيتم استدعاء جميع الطرق القابلة للتطبيق لوظيفة عامة وستتم إضافة النتائج. (defgeneric object-width (object)

في هذا الإطار، (* 10 (length (slot-value object 'text)))) فئة border-mixin. التسمية مجرد اتفاقية. لا توجد فائقين، ولا فتحات. (defclass border-mixin )

ومن جهة أخرى، bordered-button هي فئة يرث من كل من border-mixin و button. (defclass bordered-button (border-mixin button) )

من جهة ثانية، (:method-combination +)) button فئة مع فتحة واحدة لنص الزر. (defclass button

إضافةً إلى ذلك، يمكننا الآن حساب عرض الزر. استدعاء object-width يحسب 80. والنتيجة هي نتيجة الطريقة المنطبقة الوحيدة: طريقة object-width button الفئة. ? (object-width (make-instance 'button))

في هذا الإطار، يوفر Common Lisp مزيجًا في CLOS (نظام كائن Lisp المشترك) مشابهًا للنكهات.

سكالا

  • XOTcl / TclOO (نظم الكائن المضمن إلى تى سى ال)
  • sass(لغة ورقة أنماط)
  • حديث قصير
  • فالا
  • سويفت

attr_accessor :name, :score

  • def initialize(name, score)
  • @name = name
  • @score = score

// Implementation

علاوةً على ذلك، const EnumerableFirstLast = (function { // function based module pattern.

};

  • return function { // function based Flight-Mixin mechanics...
  • this.first = first; //... referring to...
  • this.last = last; //... shared code.
  • };

Object.assign(obj1, mix1, mix2);

وفي السياق ذاته، console.log(`His age is ${obj1.age} as of today`); // His age is 1897 as of today الوظيفة النقية والتفويض القائم على نهج خلط الطيران Flight-Mixin

وفي هذا الصدد، هناك نوعان من أنماط الوظائف الوظيفية يقومان بالفعل بالخدعة دون الحاجة إلى تنفيذ طرف ثالث extend. 'use strict';

وفي هذا السياق، console.log(obj1.toString); // Marcus Aurelius - Rome - 121-04-26

كذلك، على الرغم من أن النهج الموصوف أولاً منتشر في الغالب، فإن النهج التالي أقرب إلى ما يقدمه جوهر لغة جافا سكريبت بشكل أساسي - التفويض.

في بيثون

وفي هذا السياق، pass تضيف فئة ThreadingMixIn وظائف إلى خادم TCP بحيث يقوم كل اتصال جديد بإنشاء مؤشر ترابط جديد. باستخدام نفس الطريقة، يمكن إنشاء ThreadingUDPServer دون الحاجة إلى تكرار التعليمات البرمجية في ThreadingMixIn. وبدلاً من ذلك، فإن استخدام ForkingMixIn سيؤدي إلى تفرع العملية لكل اتصال جديد. من الواضح أن وظيفة إنشاء خيط جديد أو شوكة عملية ليست مفيدة بدرجة كبيرة كفئة مستقلة.

وفي هذا السياق، في بيثون، و SocketServer حدة لديه على حد سواء UDPServer الطبقة و TCPServer الصف. تعمل كخوادم لخوادم UDP وTCP socket، على التوالي. علاوةً على ذلك، هناك فئتان من mixin: ForkingMixIn و ThreadingMixIn. عادة، يتم التعامل مع جميع الاتصالات الجديدة في نفس العملية. عن طريق توسيع TCPServer باستخدام ThreadingMixIn كما يلي: class ThreadingTCPServer(ThreadingMixIn, TCPServer):

وفي هذا السياق، في مثال الاستخدام هذا، توفر المزج وظائف أساسية بديلة دون التأثير على الوظيفة كخادم مأخذ.

}

إضافةً إلى ذلك، كما extends يستعمل كذلك ليرث من صنفsuper class، إذا لم يرق أي صنف superclass في حالة استخدام trait سمة extends وفقط لmixin في سمة traitالأولى. يتم خلط جميع السمات التالية في استخدام الكلمة الأساسية with. class Person

إضافةً إلى ذلك، class Bird extends Singer هنا، اختلط Bird في جميع طرقmethods السمة trait في تعريفه الخاص كما لو كانت صنف Bird قد حددت طريقة الغناء بمفردها.

تطبيقات

من جهة ثانية، في ورقة OOPSLA 90، يعيد كل من جلعاد براخا وويليام كوك تفسير آليات الميراث المختلفة الموجودة في Smalltalk و Beta و CLOS كأشكال خاصة من ميراث المزج.

كذلك، في Simula، يتم تعريف classes في block يتم فيها تحديد السمات attributes و methods و class initialization معًا؛ وبالتالي يتم تعريف جميع الmethods التي يمكن استدعاؤها في فئة معًا، ويتم استكمال تعريف defined الصنف class.

ومن جهة أخرى، مثال على ذلك هو مزيج + الطريقة، حيث يتم إضافة القيم الناتجة لكل من الأساليب القابلة للتطبيق لوظيفة عامة حسابيًا لحساب القيمة المرتجعة. يتم استخدام هذا، مثلًا، مع mixin mixin للكائنات الرسومية. قد يكون للكائن الرسومي دالة عرض عامة. سيضيف mixin الحد إطارًا حول كائن ولديه طريقة حساب عرضه. سيحدد bordered-button جديد bordered-button border حدية للفئة (وهو عبارة عن كائن رسومي ويستعمل مزيج border) عرضه عن طريق استدعاء جميع طرق العرض القابلة للتطبيق عبر تركيبة + الطريقة. تتم إضافة جميع قيم الإرجاع وإنشاء العرض المدمج للكائن.

وعلى صعيد آخر، في Flavours، المزيج mixin هو class يمكن أن يرث من class اخر ال slot definitions and methods. لا يحتوي الخليط mixin عادة على كائنات مباشرة direct instances. بما أن Flavor يمكن أن ترث من أكثر من Flavor أخرى، يمكن أن ترث من واحد أو أكثر من mixins. لاحظ أن Flavors الأصلية لم تستعمل وظائف عامة generic functions..

من جانب آخر، CLOS و Flavours تسمح mixin methods بإضافة سلوك methodsالحالية :before و :after، اdaemons الهوامش whoppers والأغلفة wrappers wrapper or a whopper في Flavors. تمت إضافة CLOS :around methods والقدرة على استدعاء الطرق المظللة shadowed methods عبر . لذلك، مثلًا، يمكن أن يضيف دفق قفل mixin قفلًاstream-lock-mixin حول methods الحالية classstream. في Flavours، يمكن للمرء أن يكتب غلافًا أو ووبرًا وفي CLOS سيستعمل طريقة :around. يسمح كل من CLOS و Flavours بإعادة الاستخدام المحوسب من خلال تركيبات الطريقة. :before و :after و :around method هي ميزة لمجموعة الطرق القياسية. يتم توفير تركيبات طريقة أخرى.

من جانب آخر، في Flavors الجديدة (خليفة النكهات) و CLOS، يتم تنظيم الأساليب في «وظائف عامة»"generic functions". هذه الدوال العامة generic functions هي وظائف يتم تعريفها في حالات (methods) متعددة عن طريق class dispatch و method combinations.

end

def <=>(other)

@score <=> other.score

من جهة ثانية، # Including the Comparable module requires the implementing class to define the <=> comparison operator

وعلى صعيد آخر، # Here's the comparison operator. We compare 2 student instances based on their scores.

class Actor extends Person with Singer

في هذا الإطار، class Actor extends Singer with Performer Scala يسمح بالاختلاط في سمة trait (إنشاء نوع مجهول) عند إنشاء كائن جديد لصنف instance of a class. في حالة كائن من صنف الشخص، لا يمكن لجميع الكائنات الغناءsing. هذه الميزة تأتي ثم استخدام: class Person{

  • def tell { println (" Human ") }
  • //more methods
  • }
  • val singingPerson = new Person with Singer
  • singingPerson.sing

console.log(sam.fullName); // Samwise Gamgee

وفي هذا الصدد، console.log(frodo.fullName); // Frodo Baggins امزج Mixin باستخدام Object.assign 'use strict';

  • // Creating an object
  • const obj1 = {
  • name: 'Marcus Aurelius',
  • city: 'Rome',
  • born: '121-04-26'
  • };
  • // Mixin 1
  • const mix1 = {

};

من جانب آخر، // Adding the methods from mixins to the object using Object.assign

رائع

  • تفويض JavaScript - الوظائف كأدوار (السمات و Mixins)
  • Kotlin
  • less

func onError {

  • error("Please check your internet Connection.")
  • }
  • }
  • انظر كذلك
  • نوع مجرد
  • نمط الديكور
  • التصميم القائم على السياسة
  • سمة، بنية مماثلة لا تتطلب تكوينًا خطيًا
  • المراجع
  • روابط خارجية
  • MixIn في مستودع نمط بورتلاند

Mixins في ActionScript

علاوةً على ذلك، يوفر نظام الكائن المشترك Lisp: نظرة عامة بقلم ريتشارد ب.غابرييل وليندا ديميشيل مقدمة جيدة للدافع لتحديد الفئات عن طريق الوظائف العامة.

ما رأيك في هذه المقالة؟

📝 هل في هذه المقالة خطأ؟

إذا وجدت معلومة تحتاج تصحيحاً أو إضافة، أو أردت حذف المقالة، أرسل لنا طلباً وسنراجعه.