سؤال

تخيل شيئًا كهذا:

import class B.*;


interface A supports A.testSum
{
   int sum( int a , int b ) access from B.calculator;

   testSum() { Assert(sum(1,1)==2); }

........


class B ...
{
  void calculator() {  A.sum(3,5); //ok }
  void someOtherMethod() { A.sum(0,3); //compile error }

فكرة "الدعم" ثانوية ولكنها ذات صلة لأن الاختبار ينطبق على الواجهة في هذه الحالة (وبالتالي فإن اللغة ستميز بين اختبار الواجهة ، والتي يجب أن تجتازها جميع التطبيقات واختبار التنفيذ ، وهو خاص بخصوصية التنفيذ

لكن الفكرة المهمة التي أريد أن أنقلها هنا هي دلالات التحكم في الوصول ؛ لاحظ أنه لا يمكن استدعاء A.Sum مع كلمة "Access From" إلا من الطريقة B.Calculator. يتم الكشف عن أي شيء آخر كخطأ وقت الترجمة. الفكرة هنا هي فرض القيود المعمارية بطريقة أكثر حبيبًا. إذا لم تقم بإضافة "وصول من" أو فقط "الوصول إلى" من *"، فهذا يعني السلوك الافتراضي المتمثل في السماح بالطريقة التي يتم استدعاؤها من أي مكان. أي نوع من القيود المعمارية؟ حسنًا ، يتم استخدام النوع الذي يتم تطبيقه يدويًا عند القيام بتصميم طبقة: يتم استخدام الطبقة A (أدنى مستوى) من الطبقة B (المستوى المتوسط) ، والذي يستخدم بدوره من الطبقة C (المستوى العالي). لكن لا يمكن الوصول إلى الطبقة B من الطبقة A ، ولا يتم تصنيع الطبقة C من A أو B ، ولكنها عامة خلاف ذلك (قد يكون المستخدم النهائي الوصول المباشر)

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

تحديث: هناك حالة استخدام مهمة أخرى لهذا النوع من القيود:

البرمجة القائمة على الحدث: عادة ما تكون المشكلة في الحدث هي أن الأحداث تميل إلى القيام بالكثير ، وأن فهم سلسلة التبعيات للأحداث يمكن أن يصبح صعبًا

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

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

المحلول

يدعم Java شيئًا إلى حد كبير نفس الشيء.

بادئ ذي بدء ، يتم فرض رؤية الحقول والأساليب في وقت التشغيل ، ولا يمكن أن يتجاوز هذا الكود غير المحبوب.

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

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

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

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

نصائح أخرى

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

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

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

هذا يمكن فعله في روبي ، وإن كان مع بناء جملة مختلف. خذ ما يلي:

module T
    def check
        raise unless self.is_a?(Ca)
        raise unless %r{in `good_func'} =~ caller.first #`
        true
    end
end

class Ca
    include T
    def good_func
        check
    end
    def bad_func
        check
    end
end

class Cb
    include T
    def good_func
        check
    end
    def bad_func
        check
    end
end

a = Ca.new
b = Cb.new

a.good_func
=> true
a.bad_func
=> (RuntimeError)

b.good_func
=> (RuntimeError)
b.bad_func
=> (RuntimeError)

عند استخدام الوحدة النمطية كمزيج ، self يتوافق مع الفصل includeS الوحدة النمطية. caller إرجاع callstack الحالي ، و caller.first يحصل عليك الإدخال الأول على callstack (أي الوظيفة التي تسمى هذا واحد).

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