هل يلقي الصب في جافا إخفاء أساليب وحقول الفئة الفرعية؟

StackOverflow https://stackoverflow.com/questions/712528

  •  23-08-2019
  •  | 
  •  

سؤال

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

RestrictedUser restricted = regularUser;

هل يصل الصب في جافا إخفاء أساليب وحقول الفئة الفرعية أو أفعل شيئا خاطئا؟ ايوجد اي عمل في هذه المنطقه؟

شكرا

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

المحلول

إذا كنت ترغب في محاولة تشغيل هذا الرمز:

User user = new User(...);
RestrictedUser restricted = user;
restricted.methodDefinedInTheUserClass(); // <--

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

if (restricted instanceof User) {
    User realUser = (User)restricted;
    realUser.methodDefinedInTheUserClass(); // !!
}

وعدم وجود "المقيد" مقيدا بذلك بعد الآن.

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

نصائح أخرى

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

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

أنت مربكة نوع ثابت والنوع الديناميكي.

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

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

إذا كنت بحاجة إلى حماية الفئة الفرعية، فيمكنك استخدام نمط المفوض:

public class Protect extends Superclass {  // better implement an interface here
  private final Subclass subclass;

  public Protect(Subclass subclass) {
    this.subclass = subclass;
  }

  public void openMethod1(args) {
    this.subclass.openMethod1(args);
  }

  public int openMethod2(args) {
    return this.subclass.openMethod2(args);
  }
  ...
}

يمكنك أيضا التفكير في استخدام java.lang.reflect.proxy.
[]]

إجابة بيتر و جو جون صحيحة: فقط يلقي النوع الثابت لن يفعل شيئا إذا كان النوع الحقيقي للكائن (الذي يمكن أن يلقي رمز العميل، وأساليب الانعكاس، وما إلى ذلك) متاحا. يجب عليك إخفاء النوع الحقيقي بطريقة أو بأخرى (كما يذكر إجابة بيتر).

هناك بالفعل نمط للقيام بذلك: ألق نظرة على unconfigurable* الأساليب في Executors فئة، إذا كان لديك حق الوصول إلى شفرة المصدر JDK.

جاوة

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

ابق

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

تقييد الصفات

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

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

Runnable run = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello, world!");
    }

    public void secretSquirrel() {
        System.out.println("Surprise!");
    }
}

قد لا تتمكن من تسمية النوع الحقيقي من run (من أجل وضعها مباشرة)، ولكن لا يزال بإمكانك الحصول على فئتها getClass(), ، ويمكنك الاتصال secretSquirrel باستخدام التفكير. (حتى و إن secretSquirrel هو خاص، إذا كان لديك لا SecurityManager, ، أو إذا تم إعدادها للسماح بإمكانية الوصول، فيمكن للانعكاس استدعاء الأساليب الخاصة أيضا.)

أعتقد أنك ربما قدمت خيارا كبيرا في التسمية: أعتقد RestrictedUser سيكون فرعية من User, ، ليس في الاتجاه الآخر، لذلك سوف تستخدم UnrestrictedUser كما الفئة الفرعية.

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

أيضا، في Java، جميع الطرق غير الثابتة افتراضية افتراضيا. هذا يعني أنه إذا UnrestrictedUser يتجاوز بعض الطريقة المعلنة في RestrictedUser, ، ثم UnrestrictedUser سيتم استخدام الإصدار، حتى لو تموينه من خلال RestrictedUser المرجعي. إذا كنت بحاجة إلى استدعاء إصدار الفصل الأصل، فيمكنك إجراء مكالمة غير افتراضية عن طريق الاتصال RestrictedUser.variableName.someMethod(). وبعد ومع ذلك، ربما لا ينبغي أن تستخدم هذا في كثير من الأحيان (أقل الأسباب التي تنفصل عن التغليف).

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

يمكنك تحديث سؤالك لتضمين سيناريو حيث يمكنك استدعاء هذه الأساليب في السؤال؟ ربما سنكون قادرين على مساعدة المزيد.

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

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

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