캡슐화에는 목적이 있지만 오용되거나 남용 될 수도 있습니다.
수백 개의 필드가있는 클래스가있는 Android API와 같은 것을 고려하십시오. 이러한 필드를 API 소비자에게 공개하면 탐색 및 사용이 더 어려워지고 사용자는 필드 사용 방법과 충돌 할 수있는 필드로 원하는 작업을 수행 할 수 있다는 잘못된 개념을 사용자에게 제공합니다. 따라서 캡슐화는 유지 관리 성, 유용성, 가독성 및 미친 벌레를 피하는 의미에서 훌륭합니다.
다른 한편으로, 모든 필드가 공개되는 C / C ++의 구조체와 같은 POD 또는 일반 오래된 데이터 형식도 유용 할 수 있습니다. 롬복의 @data 주석에 의해 생성 된 것과 같은 쓸모없는 게터 / 세터를 갖는 것은 "봉지 패턴"을 유지하는 방법 일뿐입니다. Java에서 "쓸모없는"getter / setter를 수행하는 몇 가지 이유 중 하나는 메소드 가 계약을 제공하기 때문 입니다.
Java에서는 인터페이스에 필드를 가질 수 없으므로 getter 및 setter를 사용하여 해당 인터페이스의 모든 구현자가 갖는 공통 특성을 지정하십시오. Kotlin 또는 C #과 같은 최신 언어에서는 속성 개념을 setter 및 getter를 선언 할 수있는 필드로 봅니다. 결국, 쓸모없는 getter / setter는 오라클이 속성을 추가하지 않는 한 Java와 함께 살아야 할 유산입니다. 예를 들어 JetBrains에서 개발 한 또 다른 JVM 언어 인 Kotlin에는 기본적으로 @data 주석이 Lombok에서 수행하는 작업을 수행하는 데이터 클래스가 있습니다.
또한 몇 가지 예가 있습니다.
class DataClass
{
private int data;
public int getData() { return data; }
public void setData(int data) { this.data = data; }
}
이것은 캡슐화의 나쁜 경우입니다. 게터와 세터는 사실상 쓸모가 없습니다. 캡슐화는 Java와 같은 언어의 표준이기 때문에 주로 사용됩니다. 실제로 코드 기반에서 일관성을 유지하는 것 외에는 도움이되지 않습니다.
class DataClass implements IDataInterface
{
private int data;
@Override public int getData() { return data; }
@Override public void setData(int data) { this.data = data; }
}
이것은 캡슐화의 좋은 예입니다. 캡슐화는 계약 (이 경우 IDataInterface)을 시행하는 데 사용됩니다. 이 예제에서 캡슐화의 목적은이 클래스의 소비자가 인터페이스에서 제공하는 메소드를 사용하도록하는 것입니다. getter와 setter가 멋진 작업을 수행하지 않더라도 이제 DataClass와 다른 IDataInterface 구현 자 사이에 공통된 특성을 정의했습니다. 따라서 다음과 같은 방법을 사용할 수 있습니다.
void doSomethingWithData(IDataInterface data) { data.setData(...); }
이제 캡슐화에 대해 이야기 할 때 구문 문제를 해결하는 것이 중요하다고 생각합니다. 나는 사람들이 캡슐화 자체보다는 캡슐화를 시행하는 데 필요한 구문에 대해 불평하는 것을 종종 본다. 마음에 오는 한 가지 예는 (당신이 그의 호언 장담 볼 수 케이시 MURATORI에서입니다 여기를 ).
캡슐화를 사용하는 플레이어 클래스가 있고 자신의 위치를 1 단위 이동한다고 가정합니다. 코드는 다음과 같습니다.
player.setPosX(player.getPosX() + 1);
캡슐화가 없으면 다음과 같습니다.
player.posX++;
여기서 그는 캡슐화가 더 많은 이점을 제공하지 않으면 서 더 많은 타이핑이 가능하며 많은 경우에 맞을 수 있지만 무언가를 주목할 수 있다고 주장합니다. 인수는 캡슐화 자체가 아니라 구문에 위배됩니다. 캡슐화 개념이없는 C와 같은 언어에서도 '_'또는 'my'로 미리 접두사 또는 접두어가 붙은 구조체의 변수 또는 API 소비자가 사용하지 않아야 함을 나타내는 모든 변수를 종종 볼 수 있습니다 사유의.
문제는 캡슐화가 코드를 훨씬 더 유지 관리하고 사용하기 쉽게 만드는 데 도움이된다는 것입니다. 이 수업을 고려하십시오.
class VerticalList implements ...
{
private int posX;
private int posY;
... //other members
public void setPosition(int posX, int posY)
{
//change position and move all the objects in the list as well
}
}
이 예제에서 변수가 공개 된 경우이 API의 소비자는 posX 및 posY 사용시기와 setPosition () 사용시기에 대해 혼동 될 수 있습니다. 이러한 세부 사항을 숨기면 소비자가 직관적 인 방식으로 API를 더 잘 사용하는 데 도움이됩니다.
구문은 많은 언어에서 제한 사항입니다. 그러나 새로운 언어는 퍼블릭 멤버의 멋진 구문과 캡슐화의 이점을 제공하는 속성을 제공합니다. MSVC를 사용하는 경우 C ++, 심지어 C ++에서도 속성을 찾을 수 있습니다. 다음은 Kotlin의 예입니다.
VerticalList 클래스 : ... {var posX : Int set (x) {field = x; ...} var posY : Int set (y) {필드 = y; ...}}
여기서는 Java 예제와 동일한 결과를 얻었지만 posX와 posY를 마치 공용 변수 인 것처럼 사용할 수 있습니다. 그래도 값을 변경하려고하면 settter set () 본문이 실행됩니다.
예를 들어 Kotlin에서 이것은 getter, setter, hashcode, equals 및 toString이 구현 된 Java Bean과 같습니다.
data class DataClass(var data: Int)
이 구문을 통해 Java Bean을 한 줄로 수행하는 방법에 주목하십시오. Java와 같은 언어가 캡슐화를 구현할 때 발생하는 문제를 올바르게 알았지 만 이는 캡슐화 자체가 아닌 Java의 결함입니다.
당신은 getter와 setter를 생성하기 위해 Lombok의 @Data를 사용한다고 말했습니다. @Data라는 이름을 확인하십시오. 주로 데이터 만 저장하고 직렬화 및 역 직렬화되는 데이터 클래스에서 사용됩니다. 게임의 저장 파일과 같은 것을 생각하십시오. 그러나 UI 요소와 같은 다른 시나리오에서는 변수 값을 변경하는 것만으로는 예상되는 동작을 수행하기에 충분하지 않기 때문에 세터를 가장 명확하게 원합니다.
"It will create getters, setters and setting constructors for all private fields."
-이 도구를 설명하는 방식 은 캡슐화를 유지하는 것처럼 들립니다 . (적어도 느슨하고 자동화 된 다소 빈약 한 모델 의미에서) 문제가 정확히 무엇입니까?