NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# 17-8. 네스티드 클래스. (Nested Class)

    페이지 정보

    본문

    안녕하세요. 소심비형입니다. 오늘은 중첩(Nested) 클래스에 대해서 알아보겠습니다. 네스티드 클래스는 취향을 많이 타는 기법이라고 할 수 있습니다. 기본적으로 하나의 파일에 하나의 클래스만을 작성하는게 원칙으로 되어 있기 때문이죠. 

    Java는 하나의 파일에 하나의 클래스만 작성해야 합니다. 물론, Java도 중첩 형식으로 하나의 파일에 여러개의 클래스를 만들수는 있습니다. 하지만 기본적으로 하나의 파일에 하나의 클래스만 작성하는게 일반적인 코딩 방식입니다. 그렇다보니 C#에서도 하나의 파일에 하나의 클래스를 작성하도록 유도하는 경우가 많습니다. 또한, MS에서 배포하는 코딩 가이드에도 하나의 파일에 하나의 클래스만 작성하도록 권고하고 있습니다.

     

    C#은 강제 사항이 아닙니다. 여러개의 클래스를 하나의 파일에 정의해도 됩니다. 하지만, 이렇게 할 경우 번거로운 일이 발생됩니다. 순환 참조로 인해 파일 참조가 된 경우와 설계가 잘못되어 소스를 가지고 있음에도 불구하고 프로젝트 참조를 할 수 없을때 입니다. 이런 문제가 발생되면 Visual Studio에서 디버깅 추적이 안됩니다. 이 때는 클래스명을 보고 솔루션 탐색기에서 파일을 찾을 수 있어야 합니다. 하지만, 하나의 파일에 여러개의 클래스를 정의하다보면 이런 문제가 발생될 때 클래스를 찾는것도 귀찮게 됩니다. 보통 찾기에서 "전체 솔루션"을 선택하고 클래스명을 입력하겠죠-_-;

     

    아무튼, 중첩 형식은 그리 자주 사용되지는 않습니다. 프로젝트별로 모듈화가 되어 있기도 하고 특별한 모델이 아니고서야 클래스 내부에 데이타를 가질 필요가 없기 때문입니다. 순환 종속성을 피하기 위해 몇가지 네임스페이스를 정의하는 룰이 있기 때문에 이런 문제를 겪는 개발자는 그리 많지 않을겁니다. 제가 경험해본바로는 대부분 경력이 짧거나 OOP에 대한 이해가 부족한 개발자가 공통 모듈 개발 업무에 투입되었을 때 발생했던거 같습니다.

     

    글을 적다보니 이상한데로 빠져서 잡소리가 길어졌네요^^;

     

    아래 예제는 중첩 형식을 이용하여 내부 당원에 대한 정보를 외부에 노출시키지 않습니다. 당의 내부에서만 당원들의 정보에 접근할 수 있게 됩니다.

    using System;
    using System.Collections.Generic;
    namespace NestedClass
    {
        interface 사람
        {
            string ID
            {
                get; set;
            }
     
            string Name
            {
                get; set;
            }
        }
        abstract class 당
        {
            public virtual string 목표 { get; set; }
     
            public virtual string 이념 { get; set; }
     
            public abstract void 입당시키기(string id, string name);
        }
        class 더불어민주당 : 당
        {
            List<당원> 당원들 = new List<당원>();
     
            public 더불어민주당()
            {
                base.목표 = "정권 교체";
                base.이념 = "모든 국민이 행복한 복지 국가";
            }
     
            public override void 입당시키기(string id, string name)
            {
                당원 신입당원 = new 당원(id, name);
                신입당원.당에가입하기(this);
            }
     
            public IEnumerable<object> 이름으로당원찾기(string name)
            {
                foreach (var 당원 in 당원들)
                {
                    if (당원.Name.Equals(name))
                    {
                        yield return 당원;
                    }
                }
            }
     
            private class 당원 : 사람
            {
                public 당 정당 { get; set; }
                public string 당이름 { get { return 정당.GetType().Name; } }
                public string 당목표 { get { return 정당.목표; } }
                public string 당이념 { get { return 정당.이념; } }
                public string ID { get; set; }
                public string Name { get; set; }
     
                public 당원(string id, string name)
                {
                    ID = id;
                    Name = name;
                }
     
                public void 당에가입하기(당 정당)
                {
                    this.정당 = 정당;
                }
            }
        }
        class 새누리당 : 당
        {
            List<당원> 당원들 = new List<당원>();
     
            public 새누리당()
            {
                base.목표 = "정권 유지";
                base.이념 = "재벌과 기득권층만 행복한 독재 국가";
            }
     
            public override void 입당시키기(string id, string name)
            {
                당원 신입당원 = new 당원(id, name);
                신입당원.당에가입하기(this);
            }
     
            private class 당원 : 사람
            {
                public 당 정당 { get; set; }
                public string 당이름 { get { return 정당.GetType().Name; } }
                public string 당목표 { get { return 정당.목표; } }
                public string 당이념 { get { return 정당.이념; } }
                public string ID { get; set; }
                public string Name { get; set; }
     
                public 당원(string id, string name)
                {
                    ID = id;
                    Name = name;
                }
     
                public void 당에가입하기(당 정당)
                {
                    this.정당 = 정당;
                }
            }
        }
        class MainApp
        {
            static void Main(string[] args)
            {
                당 _더불어민주당 = new 더불어민주당();
                _더불어민주당.입당시키기("1", "문재인");
                _더불어민주당.입당시키기("2", "이재명");
                당 _새누리당 = new 새누리당();
                _새누리당.입당시키기("18", "박근혜");
                _새누리당.입당시키기("19", "김무성");
                Console.WriteLine($"{_더불어민주당.GetType().Name}의 이념: {_더불어민주당.이념}");
                Console.WriteLine($"{_새누리당.GetType().Name}의 이념: {_새누리당.이념}");
     
                foreach (사람 item in ((더불어민주당)_더불어민주당).이름으로당원찾기("이재명"))
                {
                    Console.WriteLine($"{item.Name}님은 {_더불어민주당.GetType().Name} 소속입니다.");
                }
     
                Console.WriteLine("노회찬 의원님도 화이팅 하세요!");
                Console.WriteLine("정의당 응원합니다!");
                Console.ReadKey();
            }
        }
    }

     

     

    간단하게 예제를 만들려고 했었는데, 하다보니 점점 길어져서 어떻게 할 수 없는 지경에 이르렀습니다-_-;

    중첩 형식은 외부 형식이 클래스인지 구조체인지 여부에 관계없이 기본적으로 private로 설정됩니다. Java는 public입니다. 그렇다고 해서 public, protected, internal, protected internal로 설정할 수 없는것은 아닙니다. Java도 private으로 설정할 수 있지만 컴파일러 경고를 표시해줍니다.

     

    아래 이미지는 실행한 화면입니다.

    bN6QuxZ.png

     

     

    다음 시간에...

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.