문제

저는 Java로 시작하고 세터, 게터 및 캡슐화에 대해 배우고 있습니다. 매우 간단한 프로그램과 두 가지 수업이 있습니다.

  • Container 개인 int 배열이 있습니다 (numArray) 그의 setter & getter와 함께.

  • Main a 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;
    }
}

문제 : Getter를 통해 개인 int 배열을 변경할 수 있습니다. getNumArray 참조를 반환합니다 numArray, 배열 자체가 아닙니다. 배열의 단일 요소에 관심이 있다면 인덱스 값을 가진 getter를 만들지 만 전체 배열을 원합니다. totalArray 방법.

어떻게 방지 할 수 있습니까? numArray 그의 수업에서 수정 된 것에서?

도움이 되었습니까?

해결책

사람들이 배열을 바꾸지 못하도록하기 위해 할 수있는 일은 Getter에 사본을 제공하는 것입니다.

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

이런 식으로 다른 방법은 자체 배열 사본을 변경할 수 있지만 Getter를 다시 호출하면 원래 버전을 얻지 못합니다. 오직 setNumArray() 실제로 내부 배열을 수정할 수 있습니다.

그렇지 않으면 컨테이너를 완전히 차단하려면 배열을 떨어 뜨리고 불변의 물체를 사용해야합니다. 약간 라이브러리는 불변의 목록 또는 사용을 제공합니다 Collections.unmodifiablelist.

다른 팁

배열을 반환하려면 복제 할 것입니다.

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

공개 API에서는 발신자에게 명확하게 문서화해야합니다 (실제로 클래스의 상태를 변경하거나 알 수없는 배열을 얻는 경우 어느 쪽이든 알 필요가 있습니다).

일반적으로 수업의 발신자에게 제공하려는 인터페이스를 살펴 봅니다.

다음과 같은 방법 :

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

컨테이너 클래스에서 제공 할 것입니다. 그런 다음 발신자를 대신하여 개인 배열과 상호 작용합니다.

변경 사항을 허용하지 않고 전체 배열을 반환하려면 Getter에서 배열을 새 제품으로 복사하여 사본을 반환 할 수 있습니다.

또는 원시 배열 대신 Java Collection 클래스를 사용하는 경우 Unmodifablexxx () 메소드를 제공합니다 (예 : Collections.unmodifiableList(myList)) 컬렉션 주변에 읽기 전용 랩퍼를 제공합니다.

캡슐화는 구현을 숨기는 과정입니다. 수집이 데이터를 배열에 저장하는지 여부는 구현 세부 사항입니다. 그것이 캡슐화되면 다른 스토리지 유형으로 변경할 수 있기를 원할 것입니다.

getters and setter가 캡슐화를 중단하고 진정한 객체 지향 클래스가 아닌 추상 데이터 유형을 구현하고 있음을 의미합니다. 예를 들어, an ArrayList 응용 프로그램에서 동작의 실제 캡슐화를 나타내지 않는 데이터 유형입니다. 이것이 당신이 원하는 것인지의 여부는 유형의 방법과 위치에 따라 다릅니다.

나는 만드는 경향이있다 Container 구현하다 Iterable<Integer> 단순히 컨테이너 데이터 유형 인 경우 외부 중간의 경우, 캡슐화 된 클래스로 의도 된 경우 방문자를 통과하는 내부 반복 방법을 제공합니다. 추상 데이터 유형 인 경우 다음과 같은 내장 데이터 유형을 강력히 고려하십시오. int[] 또는 List<Integer> 대신에.

배열의 사본을 만들지 않고 다른 단점이있는 또 다른 방법이 있습니다. 나는 매우 큰 배열에 그것을 사용할 것입니다.

private A[] items;

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

자바에서 배열을 캡슐화하는 방법

질문은 충분히 분명 할 수 있지만 OOP 디자인입니다 엔티티로서의 클래스 이 배열을 조작하고 자체 API를 추출합니다.

지속되면 a 클론정렬 / 방어 사본 갈 길입니다 간단한 경우.

나는 여기서 본 모든 답과 다른 접근법을 제안하고 싶습니다. 규칙을 생각하기 위해 캡슐화를 생각할 때 편리합니다. "데이터를 객체에 요청하지 말고, 객체에 데이터에서 작동하도록 요청하십시오".

당신은 나에게 용도를주지 않았다 numArray, 나는 당신의 대상이 예를 들어 수학 (Java 벡터가 아닌)에서 숫자 "벡터"를 만드는 것인 척 할 것입니다.

따라서 복식 배열이 포함 된 NumericVector 클래스를 만듭니다. NumericVector에는 방법이 있습니다 multiplyByScalar(double scalar) 및 AddVector (NumericVector SecondVector)를 추가하여 요소를 추가합니다.

내부 배열은 완전히 캡슐화되어 있습니다. 결코 탈출하지 않습니다. 이에 대한 작업은 이러한 "비즈니스 방법"을 통해 NumericVector 클래스에서 수행됩니다. 작동 후 어떻게 표시합니까? NumericVector를 재정의해야합니다 NumericVector.toString() 따라서 올바르게 인쇄하거나 GUI가있는 경우 "컨트롤러"클래스를 작성하여 모델 (NUMBERICVECTOR)에서 데이터를 뷰 (GUI)로 전송합니다. 숫자 벡터에서 요소를 스트리밍하는 방법이 필요할 수 있습니다.

이것은 또한 피해야 할 몇 가지 사항을 나타냅니다. 자동으로 세터와 게터를 생성하지 말고 캡슐화를 중단합니다. 당신은 종종 게터가 필요하지만, 여기 다른 사람들이 말했듯이, 당신은 당신의 getter가 불변의 배열의 불변 버전을 반환하도록해야합니다. 또한 가능한 한 수업을 불변으로 만들어보십시오. 내가 앞서 언급 한 그 방법 numericVector.addVector(NumericVector secondVector) 아마 수정해서는 안됩니다 numericVector 그러나 솔루션으로 새로운 숫자 벡터를 반환하십시오.

이 (그리고 일반적으로) 종종 실패한 경우는 라이브러리입니다. 진짜 배열에 약간의 기능을 추가하고 싶지만 여전히 범용 배열로 남겨두고 있습니다. 이 경우 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