سؤال

أنا نادرا ما تستخدم الميراث ، ولكن عندما أحصل أبدا استخدام المحمية سمات لأنني أعتقد أنه يكسر التغليف الموروثة الطبقات.

هل تستخدم المحمية السمات ؟ ماذا كنت تستخدم لهم ؟

هل كانت مفيدة؟

المحلول

في هذا مقابلة على تصميم مشروع القانون Venners جوشوا بلوخ, مؤلف فعالة جافا يقول:

الثقة فرعية

بيل Venners: يجب أن نثق فرعية أكثر ارتباطا وثيقا من غير فرعية?على سبيل المثال, هل من الأسهل بالنسبة فرعية تنفيذ كسر لي من أنا أن غير فرعية?في خاصة كيف تشعر حول حماية البيانات ؟

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

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

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

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

كمثال, إذا نظرتم AbstractList, سوف تجد أن هناك هي محمية طريقة لحذف مجموعة قائمة في طلقة واحدة (removeRange).لماذا هو هناك ؟ لأن لغة طبيعية لإزالة مجموعة استنادا إلى API العامة ، الاتصال subList للحصول على شبهList, ثم اتصل clear على أن الفرعيةList.دون هذا الخصوص محمية طريقة, ومع ذلك, فقط الشيء الذي clear يمكن القيام به هو مرارا وتكرارا إزالة العناصر الفردية.

تفكر في ذلك.إذا كان لديك مجموعة التمثيل, ماذا تفعل ؟ ذلك سوف مرارا انهيار مجموعة ، يفعل النظام ن العمل N مرات.لذلك سوف تأخذ الدرجة الثانية كمية من العمل ، بدلا من الخطية كمية العمل أنه ينبغي.من خلال توفير هذه محمية طريقة نسمح لأي التنفيذ التي يمكن أن بكفاءة حذف مجموعة كاملة للقيام بذلك.و أي معقول List تنفيذ يمكن حذف مجموعة أكثر كفاءة في كل مرة.

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

بيل Venners: و حماية البيانات ؟

جوش بلوك: نفس الشيء, ولكن حتى أكثر من ذلك.حماية البيانات هو أكثر خطير حيث لخبطة البيانات الثوابت.إذا كنت تعطي شخص ما آخر الوصول إلى بعض البيانات الداخلية ، لديهم حرية أكثر من ذلك.

النسخة القصيرة:فإنه يكسر التغليف لكنه شر لا بد منه يجب أن يكون الحد الأدنى.

نصائح أخرى

C#:

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

قد تحتاج لهم ثابت (أو 'العالمية') سمة كنت تريد الخاص بك أو فئات فرعية من نفس الحزمة (إذا كان عن جافا) أن تستفيد من.

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

سكوت مايرز يقول لا استخدام حماية السمات في فعالية C++ (3rd ed.):

البند 22:أعلن أعضاء البيانات الخاصة.

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

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

على protected الكلمة هي المفاهيم الخطأ و لغة تصميم قرح و العديد من اللغات الحديثة ، مثل نيم و سيلان (انظر http://ceylon-lang.org/documentation/faq/language-design/#no_protected_modifier), التي تم تصميمها بعناية بدلا من مجرد نسخ الأخطاء الشائعة, لا تملك مثل هذه الكلمة.

انها ليست محمية الأعضاء أن يكسر التغليف ، إنه تعريض الأعضاء التي لا ينبغي أن يتعرض أن يكسر التغليف ...لا يهم ما إذا كانت محمية أو العامة.المشكلة protected هو الخاطئة والمضللة ...معلنا أعضاء protected (بدلا من private) لا حماية لهم, فإنه لا العكس ، تماما كما public لا.محمية الأعضاء, التي يمكن الوصول إليها من خارج الطبقة ، يتعرض العالم و لذلك دلالات يجب الحفاظ عليها إلى الأبد ، تماما كما هو الحال بالنسبة public.الفكرة كلها من "محمية" هو هراء ...التغليف ليست أمنية ، الكلمة فقط يعزز الخلط بين البلدين.يمكنك أن تساعد قليلا عن طريق تجنب جميع الاستخدامات protected في الطبقات الخاصة بك -- إذا كان هناك شيء داخلي جزء من التنفيذ ، ليس جزءا من الطبقة دلالات, و قد يتغير في المستقبل ، ثم جعلها خاصة أو الداخلية إلى الحزمة الخاصة بك, وحدة, الجمعية, الخ.إذا كان هو غير قابل للتغيير جزء من الطبقة دلالات ، ثم جعله العامة ، ومن ثم لن تزعج المستخدمين من فئة الذين يمكن أن نرى أن هناك فائدة الأعضاء في الوثائق ولكن لا يمكن استخدامه ، ما لم يتم إنشاء الخاصة بهم من الحالات يمكن الحصول على ذلك من خلال subclassing.

لا تستخدم حماية السمات في جافا لأنها ليست سوى حزمة الحماية هناك.ولكن في C++, أنا استخدامها في فئات مجردة ، والسماح وراثة الطبقة وراثة لهم مباشرة.

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

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

لقد عملت في الآونة الأخيرة على المشروع "المحمية" عضو كان فكرة جيدة جدا.الطبقة hiearchy كان شيئا مثل:

[+] Base
 |
 +--[+] BaseMap
 |   |
 |   +--[+] Map
 |   |
 |   +--[+] HashMap
 |
 +--[+] // something else ?

القاعدة نفذت std::قائمة ولكن لا شيء آخر.الوصول المباشر إلى القائمة كان يحظر على المستخدم ، ولكن قاعدة الطبقة كانت ناقصة ، يعتمد على أي حال في الفئات المشتقة لتنفيذ المراوغة إلى القائمة.

على المراوغة يمكن أن تأتي في اثنين من النكهات:الأمراض المنقولة جنسيا::خريطة stdext::hash_map.كل الخرائط سوف تتصرف بنفس الطريقة ولكن الحقيقة hash_map يحتاج مفتاح hashable (في VC2003, castable إلى size_t).

لذا خريطة الأساس نفذت TMap مثل قالب نوع الخريطة مثل الحاويات.

خريطة HashMap اثنين من الفئات المشتقة من الأساس ، واحدة متخصصة خريطة الأساس على std::خريطة الأخرى على stdext::hash_map.

لذلك:

  • قاعدة لا يمكن استخدامها على هذا النحو (أي العامة accessors !) فقط المقدمة السمات المشتركة رمز

  • خريطة أساس حاجة سهلة القراءة/الكتابة إلى std::قائمة

  • خريطة HashMap حاجة سهلة القراءة/الكتابة الوصول إلى TMap المحددة في خريطة الأساس.

بالنسبة لي الحل الوحيد هو استخدام المحمية من أجل std::قائمة TMap الأعضاء المتغيرات.لم يكن هناك أي وسيلة وأود أن وضع تلك "خاصة" لأن أنا على أي حال تعرض كل أو تقريبا كل من هذه الميزات من خلال قراءة/كتابة accessors على أي حال.

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

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

أنا استخدامها.باختصار, انها طريقة جيدة إذا كنت تريد أن يكون لها بعض السمات المشتركة.منح, يمكنك أن تكتب مجموعة/الحصول على وظائف لهم ، ولكن إذا كان هناك أي صحة ، ثم ما هي النقطة ؟ كما أنها أسرع.

النظر في هذا:لديك الدرجة التي هي الفئة الأساسية.فقد عدد غير قليل من سمات وان لا تستخدم في الأطفال الكائنات.يمكن أن تكتب الحصول على/مجموعة وظيفة لكل, أو يمكنك فقط تعيين لهم.

بلدي مثال نموذجي هو ملف/تيار معالج.كنت ترغب في الوصول إلى معالج (أيملف واصف) ، ولكن كنت ترغب في إخفاء ذلك من الفئات الأخرى.انها أسهل من كتابة مجموعة/الحصول على وظيفة من أجل ذلك.

في عام ، نعم.محمية الأسلوب هو الأفضل عادة.

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

في الآونة الأخيرة لقد جئت فصل الأشياء يمكنك القيام به مع الأوليات الخام مجموعات من الأشياء يمكنك القيام به مع تشكيل الطبقات.الأوليات والمجموعات يجب أن تكون دائما خاصة.

أيضا, لقد بدأت أحيانا تعريض الجمهور الأعضاء المتغيرات عندما declaired النهائي بشكل جيد شكلت الفئات التي ليست مرنة جدا (مرة أخرى ، ليس من الأوليات أو مجموعات).

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

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

إذا كان المستخدمون الفوضى مع فئة ليست مشكلتك.كل الخبيثة يمكن للمستخدم إضافة الأسطر التالية عند تجاوز واحد من virtuals:

(C#)

static Random rnd=new Random();
//...
if (rnd.Next()%1000==0) throw new Exception("My base class sucks! HAHAHAHA! xD");
//...

لا يمكنك ختم كل فصل لمنع هذا.

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

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

(C#):

private _foo;
public foo
{
   get {return _foo;}
   set {_foo=value;}
}

كان هذا رأيي الشخصي.

ولكن هل ما رئيسك تتطلب (إذا أراد حقول خاصة من فعل ذلك.)

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

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

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

التغليف كبيرة ، ولكن يمكن أن تؤخذ بعيدا.رأيت الطبقات التي الخاصة طرق الوصول إليها الأعضاء المتغيرات فقط باستخدام جالبة/واضع طرق.هذا مبالغة ، إذ إن فئة لا تستطيع أن تثق بنفسها أساليب خاصة مع البيانات الخاصة الذين يمكن أن تثق به ؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top