سؤال

أنا بدأت مع جافا وأنا أتعلم عن setters، getters والتغليف. لدي برنامج بسيط للغاية، فئتين:

  • Container لديه مجموعة int الخاصة (numArray) مع رصيفه و getter.

  • Main يخلق أ Container كائن ويستخدمه في totalArray طريقة.


public class Container {
    private int numArray[]= {0,0,0};
    public int[] getNumArray() {
        return numArray;
    }
    public void setNumArray(int index, int value){
        numArray[index] = value;
    }    
}

public class Main {
    public static void main(String[] args) {
        Container conte = new Container();
        System.out.println(totalArray(conte.getNumArray()));
        conte.getNumArray()[2]++;
        System.out.println(totalArray(conte.getNumArray()));
    }
    private static int totalArray (int v[]){
        int total=0;
        for (int conta =0; conta<v.length;conta++){
            total+=v[conta];
        }
        return total;
    }
}

المشكلة: يمكنني تغيير مجموعة int الخاصة من خلال Getter، وأنا أعلم ذلك getNumArray إرجاع إشارة إلى numArray, ، وليس الصفيف نفسه. إذا كنت مهتما بعنصر واحد في الصفيف، فسأخذ جيب بقيمة فهرس، لكنني أريد الصفيف بأكمله totalArray طريقة.

كيف يمكنني منع numArray من التعديل من صفه؟

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

المحلول

كل ما يمكنك فعله لمنع الأشخاص من تغيير صفيفك هو توفير نسخة منه في Getter.

public int[] getArray() {
    return Arrays.copyOf(numArray, numArray.length);
}

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

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

نصائح أخرى

إذا كنت ترغب في إرجاع صفيف، فستنسخ:

  public int[] getArray() {
       return (int[]) numArray.clone();
  }

في API العام، يجب عليك تأكد من توثيق المستند بوضوح للمتصلين (في كلتا الحالتين حقا، إذا حصلوا على صفيف سيغير حالة الفصل أم لا - يحتاجون إلى معرفة).

عادة ما ستنظر إلى الواجهة التي تحاول تقديمها للمتصلين في صفك.

طرق مثل:

void addItem(Object item);
Object getItem(int index);
int getSize();

هل هناك نوع من الأشياء التي ستوفرها في فئة الحاويات الخاصة بك. ثم يتفاعلون مع الصفيف الخاص في نيابة المتصل.

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

بدلا من ذلك، إذا كنت تستخدم فئات مجموعة Java بدلا من الصفيف البدائي، فإنها توفر طريقة unmodifablexxx () Collections.unmodifiableList(myList)) التي توفر مجمع للقراءة فقط حول المجموعة.

التغليف هي عملية إخفاء التنفيذ. ما إذا كانت المجموعة تخزن بياناتها في صفيف أو لا تفاصيل تنفيذ؛ إذا تم تغليفه، فأنت تريد أن تكون قادرا على تغييره إلى نوع تخزين آخر.

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

سوف أميل إما Container ينفذ Iterable<Integer> بالنسبة للتقسيط الخارجي إذا كان ببساطة نوع بيانات الحاويات، أو قم بتوفير طريقة للمقتطف الداخلي الذي تقوم به زائر إذا كان يهدف كطبقة مغلفة. إذا كان نوع البيانات مجردة، ففكر بشدة باستخدام تلك المدمجة مثل int[] أو List<Integer> في حين أن.

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

private A[] items;

public List<A> getItems() {
    return Collections.unmodifiableList(Arrays.asList(items));
}

كيفية تغليف صفيف في جافا

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

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

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

أنت لم تعطيني استخدام numArray, ، سأتظاهر هدفك هو إنشاء "متجه" رقمي من الرياضيات (وليس ناقلات Java) على سبيل المثال أغراض.

لذلك تقوم بإنشاء فئة NumericVector التي تحتوي على مجموعة من الزوجي. سيكون لديك numericvector الخاص بك أساليب مثل multiplyByScalar(double scalar) و ALDVECTOR (NumericVector SecondVector) لإضافة عناصر.

يتم تغليف الصفيف الداخلي بالكامل - لا يهرب أبدا. تتم أي عملية تم إجراؤها في فئة NumericVector عبر هذه "طرق العمل" هذه. كيف تعرضه بعد العمل عليه؟ لديك numericvector تجاوز NumericVector.toString() لذلك يطبع بشكل صحيح، أو إذا كان لديك واجهة المستخدم الرسومية، اكتب فئة "وحدة تحكم" لنقل البيانات من النموذج الخاص بك (العددية) إلى عرضك (GUI). قد يتطلب هذا وسيلة لدفق العناصر من NumericVector الخاص بك.

هذا يشير أيضا إلى بعض الأشياء التي يجب تجنبها: لا تقوم تلقائيا بإنشاء Setters and Jetters، فهي كسر التغليف الخاص بك. غالبا ما تحتاج إلى الحصول على Getters ولكن، كما قال آخرون هنا، يجب أن تجعل Getter عودة إصدارا ثابتا من الصفيف. حاول أيضا أن تجعل فصولك ثابتة كلما أمكن ذلك. هذه الطريقة التي ذكرتها في وقت سابق numericVector.addVector(NumericVector secondVector) ربما لا تعدل numericVector ولكن إرجاع numericvector جديد مع الحل.

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

طريقة فعالة للذاكرة للقيام بذلك ...

package com.eric.stackoverflow.example;

import java.util.List;

import com.google.common.collect.ImmutableList;

public class Container {
    private int numArray[] = {0, 0, 0};
    public int[] getNumArray() {
        return ImmutableList.copyOf(numArray);
    }
    public void setNumArray(int index, int value) {
        numArray[index] = value;
    }    
}

هذا يسمح لل ImmutableList لتعيين العدد الصحيح للعناصر في صفيف دعم List ويقلل من عدد الكائنات الوسيطة التي تم إنشاؤها.

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