IT 야놀자/C #

일반화 프로그래밍

주니어로빈 2019. 10. 29. 19:34
728x90
728x90

1. 일반화(Generalization)란?

 

'일반화'는 간단히 말해 서로 다른 개념에서 공통점을 찾는 것이다.

'A' 와 'B', 'C'는 분명 다른 단어이지만 '영어'라는 공통점을 가지며

"ABC"와 "가나다"는 분명 다른 글자이지만 '문자'라는 공통점을 가진다.

이렇듯 어떤 개념을 포괄하는 공통된 개념을 찾아 서러 다른 개념들을 하나로 묶어 줄 수 있다.

이것을 일반화(Generalization)라고 한다.

 

 

2. 일반화 메소드

 

그럼 프로그래밍에서도 이런 일반화가 가능하지 않을까?

코드의 서로 다른 개념들 사이에서 공통적인 개념을 찾아 하나의 코드로 묶어주는 것 말이다.

예를들어 int, float, string 등은 분명 다른 타입이다.

하지만 이들은 '변수'라는 개념으로 묶어줄 수 있다.

 

이전에는 int, float, string을 다른 개념으로 보고 다른 코드를 사용하였다면

이제는 이들을 변수라는 하나의 개념으로 보고 하나의 코드로 만들어 줄 수 있겠다.

 

서로 다른 타입이 여러개 있을 때 이들을 출력하는 메소드를 일일이 만들어 주는 것보단

위와 같이 일반화 과정을 거쳐 하나의 메소드로 만들어주는 것이 훨씬 효율적이다.

이를 일반화 메소드하고 하며 일반화 메소드는 다음과 같이 호출할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
namespace Cs_Lecture
{
    class Program
    {
        static void print<T>(T value)
        {
            Console.WriteLine(value);
        }
 
        static void Main(string[] args)
        {
            int age = 29;
            float height = 178.1f;
            string name = "Mr.W";
 
            print<int>(age);
            print<float>(height);
            print<string>(name);
        }
    }
}
 
 

 

print<T> 에서 T 에 원하는 타입을 지정하면 print 메소드 내부의 T 가 전부 지정한 변수로 치환되며

지정된 변수로 메소드가 실행된다.

즉, 위 예제에서처럼 int형을 지정하면 int형 데이터가 출력되고

float형을 지정하면 float형 데이터가, string형을 지정하면 string형 데이터가 출력되는 것이다.

(여기에서 T 는 형식매개변수하고 하여 형식(타입)을 지정해주는 역학을 한다.

  하지만 형식매개변수로 반드시 T 만 사용가능한 것은 아니며

  단순히 치환을 해주는 문자이기 때문에 T 외에 어떤 문자도 사용가능하다. 한글도 가능.)

 

 

3. 일반화 클래스

 

클래스도 마찬가지로 일반화된 클래스를 만들 수 있다.

예를 들어 여러 타입의 자료구조 클래스를 만든다고 했을 때

타입마다 서로 다른 클래스를 만드는 것은 상당히 비효율적이다.

이럴 때에 일반화 메소드를 만들었던 거과 마차가지로 모든 타입을 포괄하는

하나의 일반화 클래스를 만들 수 있다.

 

간단하게 예제를 만들어 보면 다음과 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace Cs_Lecture
{
    class List<T>
    {
        public T[] arr;
 
        public List() { arr = new T[1]; }
    }
 
 
    class Program
    {
        static void Main(string[] args)
        {
            List<int> list1 = new List<int>();
            list1.arr[0= 10;
            List<float> list2 = new List<float>();
            list2.arr[0= 2.2f;    
            List<string> list3 = new List<string>();
            list3.arr[0= "일반화 클래스";
 
            Console.WriteLine(list1.arr[0]);
            Console.WriteLine(list2.arr[0]);
            Console.WriteLine(list3.arr[0]);
        }
    }
}
 
 

 

 

4. T 변수 제약조건 만들기

 

지금까지 만든 일반화 메소드와 일반화 클래스는 모든 타입의 변수를 처리할 수 있었다.

다시 말해(타입)을 지정하는 매개변수 T 는 모든 타입으로 치환이 가능했다.

하지만 만약에 이 매개변수 T 를 특정 조건을 갖춘 타입으로만 치환이 가능하도록

제한하고 싶다면 어떻게 해야할까?

이때 사용하는 것이 "Where T : 제약조건" 이다.

'where T' 라는 건 T 가 어디에 있어야 한다(어디에 속해야 한다)라는 의미로 해석될 수 있겠다.

즉 where이라는 키워드로 T 의 타입 범위를 지정해주는 것이다.

 

                               where 형식매개변수 : 제약조건

                               class List<T> where T : class

                               {

                                       // ...

                                }

                                void Print<U> where U : struct

                                {

                                       // ...

                                }

 

예를 들어 'where T : class'라 하면 "형식 매개변수 T 의 타입은 class여야 한다." 라는 것이고

'where T : struct'라 하면 "T 의 타입이 값(int, float 등등...)이어야 한다.' 라는 것이다.

이외에더 형식매개변수의 제약조건은 여러가지가 있다.

 

where T : new() T 는 매개변수가 없는 생성자를 가진 타입이어야 한다.
where T : 클래스 이름 T 는 지정한 클래스이거나 이를 상속받는 클래스이어야 한다.
where T : 인터페이스 이름 T 는 인터페이스를 상속받는 클래스 이어야 한다.
where T : U T 는 형식매개변수 U 의 타입이거나, 이를 상속받는 클래스 이어야 한다.

 

간단한 예제를 보면 다음과 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
namespace Cs_Lecture
{
    class Parent
    {
        public string name { set; get; }
 
        public Parent() { name = "부모클래스"; }
    }
 
    class Children : Parent
    {
        public Children() { name = "자식클래스"; }
    }
 
    class List<T> where T : Parent
    {
        public T[] array;
 
        public List() { array = new T[2]; }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            List<Parent> list = new List<Parent>();
 
            list.array[0= new Parent();
            list.array[1= new Children();
 
            Console.WriteLine(list.array[0].name);
            Console.WriteLine(list.array[1].name);
        }
    }
}
 
 

 

728x90
728x90