언제 그리고 왜 중첩 클래스를 사용해야합니까?


30

Object Oriented Programming을 사용하면 클래스 (중첩 클래스) 내에 클래스를 만들 수 있지만 4 년 동안 코딩 경험에서 중첩 클래스를 만들지 않았습니다.
중첩 클래스는 무엇입니까?

클래스가 중첩되어 있으면 클래스를 비공개로 표시 할 수 있고 포함 클래스에서 해당 클래스의 모든 비공개 멤버에 액세스 할 수 있음을 알고 있습니다. 포함하는 클래스 자체에서 변수를 개인용으로 넣을 수 있습니다.
그렇다면 왜 중첩 클래스를 작성합니까?

어떤 시나리오에서 중첩 클래스를 사용해야합니까? 아니면 다른 기술보다 사용 측면에서 더 강력합니까?


1
당신은 좋은 답변을 가지고 때로는 수업 시간에 필요한 노동 수업이나 스트럿이있을 것입니다.
paparazzo

답변:


19

중첩 클래스의 주요 기능은 클래스 자체의 모든 기능을 사용하면서 외부 클래스의 개인 멤버에 액세스 할 수 있다는 것입니다. 또한 특정 상황에서 매우 강력한 캡슐화를 허용하는 비공개 일 수 있습니다.

여기서 클래스는 개인이 아니기 때문에 setter를 팩토리에 완전히 잠급니다. 어떤 소비자도 다운 캐스트하여 setter에 액세스 할 수 없으며 허용되는 것을 완전히 제어 할 수 있습니다.

public interface IFoo 
{
    int Foo{get;}      
}
public class Factory
{
    private class MyFoo : IFoo
    {
        public int Foo{get;set;}
    }
    public IFoo CreateFoo(int value) => new MyFoo{Foo = value};
}

그 외에는 개인 구성원에 계속 액세스 할 수있는 제어 된 환경에서 타사 인터페이스를 구현하는 데 유용합니다.

예를 들어 어떤 인터페이스의 인스턴스를 다른 객체에 제공하려고했지만 메인 클래스가 구현하기를 원하지 않는다면 내부 클래스가 구현하도록 할 수 있습니다.

public class Outer
{
    private int _example;
    private class Inner : ISomeInterface
    {
        Outer _outer;
        public Inner(Outer outer){_outer = outer;}
        public int DoStuff() => _outer._example;
    }
    public void DoStuff(){_someDependency.DoBar(new Inner(this)); }
}

대부분의 경우 나는 대표가 두 번째 예에 표시하고 일을하는 청소기 방법이 기대
벤 아 론슨

@ BenAaronson 델리게이트를 사용하여 임의의 인터페이스를 어떻게 구현 하시겠습니까?
Esben Skov Pedersen

귀하의 예를 들어 음을 @EsbenSkovPedersen, 대신 인스턴스를 전달하는 Outer, 당신은을 통과 것 Func<int>단지가 될 것이다,() => _example
벤 아 론슨

이 매우 간단한 경우에 @BenAaronson이 맞지만 더 복잡한 예의 경우 너무 많은 대의원이 서투르게됩니다.
Esben Skov Pedersen

@EsbenSkovPedersen : 예제에는 장점이 있지만, Inner중첩 internal되지 않고 작동하지 않는 경우 (예 : 다른 어셈블리를 다루지 않는 경우)에만 IMO를 사용해야합니다 . 중첩 클래스에서 가독성을 높이면 internal(가능한 경우) 사용하는 것보다 덜 유리 합니다.
Flater

23

일반적으로 중첩 클래스 N은 C 외부에서 절대로 사용해서는 안되는 내부적으로 무언가를 사용해야 할 때마다 그리고 어떤 이유로 인해 기존의 객체가 아닌 새로운 유형의 객체가되어야하는 어떤 이유로 C 클래스 내부에 생성됩니다. 유형.

나는 이것이 인터페이스를 구현하는 객체를 반환하는 메소드를 구현하는 것이 가장 자주 발생한다고 생각하며, 그 객체의 구체적인 유형은 다른 곳에서는 유용하지 않기 때문에 숨기고 싶습니다.

IEnumerable을 구현하는 것이 좋은 예입니다.

class BlobOfBusinessData: IEnumerable<BusinessDatum>
{
    public IEnumerator<BusinessDatum> GetEnumerator()
    {
         return new BusinessDatumEnumerator(...);
    }

    class BusinessDatumEnumerator: IEnumerator<BusinessDatum>
    {
        ...
    }
}

외부인이 BlobOfBusinessData콘크리트 BusinessDatumEnumerator유형 을 알고 관심 을 가질 이유가 없으므로 내부에 보관할 수도 있습니다 BlobOfBusinessData.

그것은 IEnumerable제대로 구현하는 방법에 대한 "모범 사례"가 아니라 아이디어를 얻는 데 필요한 최소한의 것이므로 명시 적 IEnumerable.GetEnumerator()방법 과 같은 것을 생략했습니다 .


6
최신 프로그래머와 함께 사용하는 또 다른 예는의 Node클래스입니다 LinkedList. 를 사용하는 사람 은 내용에 액세스 할 수있는 한 구현 LinkedList방법에 신경 쓰지 않습니다 Node. 전혀 신경 쓰지 않는 유일한 실체는 LinkedList클래스 자체입니다.
Mage Xy

3

그렇다면 왜 중첩 클래스를 작성합니까?

몇 가지 중요한 이유를 생각할 수 있습니다.

1. 캡슐화 사용

여러 번 중첩 클래스는 클래스의 구현 세부 사항입니다. 메인 클래스의 사용자는 자신의 존재에 신경 쓸 필요가 없습니다. 메인 클래스의 사용자가 코드를 변경하지 않고도 자유롭게 변경할 수 있어야합니다.

2. 이름 오염을 피하십시오

해당 범위에 적합하지 않은 한 범위에 유형, 변수, 함수 등을 추가해서는 안됩니다. 이것은 캡슐화와 약간 다릅니다. 중첩 유형의 인터페이스를 표시하는 것이 유용 할 수 있지만 중첩 유형의 적절한 위치는 여전히 기본 클래스입니다. C ++ 랜드에서 반복자 유형이 그러한 예 중 하나입니다. 나는 C #에서 당신에게 구체적인 예제를 줄만큼 충분히 경험이 없다.

중첩 클래스를 기본 클래스와 동일한 범위로 이동하는 것이 이름 오염 인 이유를 보여주는 간단한 예를 만들어 보겠습니다. 연결된 목록 클래스를 구현한다고 가정 해 봅시다. 일반적으로

publid class LinkedList
{
   class Node { ... }
   // Use Node to implement the LinkedList class.
}

당신이 이동하기로 결정하는 경우 Node와 동일한 범위까지 LinkedList, 당신은 할 것

public class LinkedListNode
{
}

public class LinkedList
{
  // Use LinkedListNode to implement the class
}

LinkedListNodeLinkedList클래스 자체가 없으면 유용하지 않을 것입니다. 사용자 가 사용할 수 LinkedList있는 LinkedListNode객체를 반환 하는 일부 함수를 제공 하더라도 사용 되는 경우 에만 유용합니다 . 따라서 "노드"클래스를 피어 클래스로 만드는 것은 포함 범위를 오염시키는 것입니다.LinkedListLinkedListNodeLinkedListLinkedList


0
  1. 관련 도우미 클래스에 공용 중첩 클래스를 사용합니다.

    public class MyRecord {
        // stuff
        public class Comparer : IComparer<MyRecord> {
        }
        public class EqualsComparer : IEqualsComparer<MyRecord> {
        }
    }
    MyRecord[] array;
    Arrays.sort(array, new MyRecord.Comparer());
    
  2. 관련 변형에 사용하십시오.

    // Class that may or may not be mutable.
    public class MyRecord {
        protected string name;
        public virtual String Name { get => name; set => throw new InvalidOperation(); }
    
        public Mutable {
            public override String { get => name; set => name = value; }
        }
    }
    
    MyRecord mutableRecord = new MyRecord.Mutable();
    

발신자는 어떤 버전이 어떤 문제에 적합한 지 선택할 수 있습니다. 때로는 한 번에 클래스를 완전히 구성 할 수 없으며 변경 가능한 버전이 필요합니다. 주기적 데이터를 처리 할 때는 항상 해당됩니다. 가변은 나중에 읽기 전용으로 변환 할 수 있습니다.

  1. 내부 기록에 사용합니다

    public class MyClass {
        List<Line> lines = new List<Line>();
    
        public void AddUser( string name, string address ) => lines.Add(new Line { Name = name, Address = address });
    
        class Line { string Name; string Address; }
    }
    

0

중첩 클래스클래스의 인스턴스를 두 번 이상 만들거나 해당 유형을 더 유용하게 만들 때마다 사용할 수 있습니다.

중첩 클래스 는 캡슐화를 증가시킬뿐만 아니라 더 읽기 쉽고 유지 보수가 쉬운 코드로 이어집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.