명확히하기 위해, 내가 묻는 것은
public class A{
private/*or public*/ B b;
}
vs.
public class A{
private/*or public*/ class B{
....
}
}
나는 분명히 하나 또는 다른 것을 사용해야하는 몇 가지 이유를 생각할 수 있지만 실제로보고 싶은 것은 장단점이 학문이 아니라는 것을 보여주는 설득력있는 예입니다.
답변
일반적으로 클래스가 외부 인터페이스의 일부가 아닌 다른 클래스의 내부 구현 세부 정보 인 경우에 사용됩니다. 나는 그것들을 c 스타일 구조체에 대한 별도의 구문이없는 언어로 내부 데이터 구조를 더 깨끗하게 만드는 데이터 전용 클래스로 보았습니다. 이벤트 핸들러 또는 작업자 스레드와 같이 고도로 사용자 정의 된 단일 메소드 파생 오브젝트에도 유용합니다.
답변
트리, 목록, 그래프 등을 작성한다고 가정하십시오. 노드 또는 셀의 내부 세부 사항을 외부 세계에 노출해야하는 이유는 무엇입니까?
그래프 또는 목록을 사용하는 사람은 나중에 언젠가 (예 : 배열 기반 구현에서 포인터 기반으로 변경) 클라이언트를 사용하여 변경하려는 경우 구현이 아닌 인터페이스에만 의존해야합니다. 데이터 구조 ( 각각 )는 새로운 구현에 적합하도록 코드를 수정해야합니다.
대신 개인 내부 클래스에서 노드 또는 셀의 구현을 캡슐화하면 클라이언트가 데이터 구조의 인터페이스가 유지되는 한 결과적으로 코드를 강제로 조정하지 않고도 필요할 때마다 구현을 자유롭게 수정할 수 있습니다. 손대지 않은.
데이터 구조 구현의 세부 사항을 숨기면 보안 이점도 생길 수 있습니다. 클래스를 배포하려는 경우 인터페이스 파일 만 컴파일 된 구현 파일과 함께 사용할 수있게되므로 실제로 배열이나 포인터를 사용하고 있는지 아무도 알 수 없기 때문에 구현을 위해 코드를 오용하거나 검사 할 수 없기 때문에 어떤 종류의 착취 또는 적어도 지식으로부터 응용 프로그램을 보호하십시오. 실제적인 문제 외에도 그러한 경우에 매우 우아한 솔루션이라는 사실을 과소 평가하지 마십시오.
답변
제 생각 에는 특정 작업을 허용하기 위해 클래스에서 간략하게 사용되는 클래스에 내부 정의 클래스를 사용하는 것이 공정한 경찰 입니다.
예를 들어, 두 개의 관련되지 않은 클래스로 구성된 데이터 목록을 바인딩해야하는 경우 :
public class UiLayer
{
public BindLists(List<A> as, List<B> bs)
{
var list = as.ZipWith(bs, (x, y) => new LayerListItem { AnA = x, AB = y});
// do stuff with your new list.
}
private class LayerListItem
{
public A AnA;
public B AB;
}
}
다른 클래스에서 내부 클래스를 사용하는 경우 별도의 클래스를 사용해야합니다. 내부 클래스에 논리가 포함되어 있으면이를 별도로 배치해야합니다.
기본적으로 데이터 객체에 구멍을 뚫는 데는 훌륭하지만 실제로 로직을 포함 해야하는 경우 유지 관리가 어렵습니다. 변경해야 할 경우 어디를 찾아야하는지 알아야하기 때문입니다.
답변
-
일부 언어 (예 : Java)의 내부 클래스는 포함 클래스의 객체와 연결되어 있으며 자격을 갖추지 않고 멤버를 사용할 수 있습니다. 가능한 경우 다른 언어 기능을 사용하여 다시 구현하는 것보다 명확합니다.
-
다른 언어 (예 : C ++)의 중첩 클래스에는 그러한 넥타이가 없습니다. 클래스에서 제공하는 범위 및 접근성 컨트롤을 사용하기 만하면됩니다.
답변
내부 클래스가있는 경우 핫 스왑이 작동하지 않으므로 Java에서 내부 클래스를 피하십시오. 이러한 고려 사항에 대한 코드를 손상시키는 것이 정말로 싫어하기 때문에 이것을 싫어하지만 Tomcat이 다시 시작됩니다.
답변
개인 정적 내부 클래스의 사용 중 하나는 메모 패턴입니다. 기억해야 할 모든 데이터를 개인 클래스에 넣고 일부 함수에서 Object로 반환합니다. 외부의 누구도 (반사, 역 직렬화, 메모리 검사없이) 그것을 조사 / 수정할 수 없지만 클래스에 되돌려주고 상태를 복원 할 수는 없습니다.
답변
개인 내부 클래스를 사용하는 한 가지 이유는 사용하는 API가 특정 클래스에서 상속을 요구하기 때문에 해당 클래스의 지식을 외부 클래스의 사용자에게 내보내고 싶지 않기 때문일 수 있습니다. 예를 들면 다음과 같습니다.
// async_op.h -- someone else's api.
struct callback
{
virtual ~callback(){}
virtual void fire() = 0;
};
void do_my_async_op(callback *p);
// caller.cpp -- my api
class caller
{
private :
struct caller_inner : callback
{
caller_inner(caller &self) : self_(self) {}
void fire() { self_.do_callback(); }
caller &self_;
};
void do_callback()
{
// Real callback
}
caller_inner inner_;
public :
caller() : inner_(*this) {}
void do_op()
{
do_my_async_op(&inner_);
}
};
여기에서 do_my_async_op는 콜백 유형의 객체를 전달해야합니다. 이 콜백에는 API가 사용 하는 공개 멤버 함수 서명이 있습니다.
do_op ()가 outer_class에서 호출되면 자체 내부 포인터 대신 필요한 콜백 클래스에서 상속되는 전용 내부 클래스의 인스턴스를 사용합니다. 외부 클래스에는 콜백을 외부 클래스의 전용 do_callback 멤버 함수 로 분류하기위한 목적으로 외부 클래스에 대한 참조가 있습니다.
이것의 장점은 아무도 “public (fire)”멤버 함수를 호출 할 수 없다는 것입니다.