2019년 5월 20일 월요일

텍스트 파일을 처리하는 프레임워크

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
namespace TextFilePorcessor
 
{
 
    public abstract class TextProcessor
 
    {
 
 
 
        public static void Run<T>(string fileName) where T : TextProcessor, new()
 
        {
 
            var self = new T();
 
            self.Process(fileName);
 
        }
 
 
 
        private void Process(string fileName)
 
        {
 
            Initialize(fileName);
 
            using (var sr = new StreamReader(fileName))
 
            {
 
                while (!sr.EndOfStream)
 
                {
 
                    string line = sr.ReadLine();
 
                    Execute(line);
 
                }
 
            }
 
            Terminate();
 
        }
 
 
 
        protected virtual void Initialize(string fname) { }
 
        protected virtual void Execute(string line) { }
 
        protected virtual void Terminate() { }
 
    }
 
}
cs

TextProcessor 클래스는 abstract(추상)를 붙였으므로 TextProcessor 클래스로부터 상속되다는 것을 전제로 한 클래스입니다.

Run이라는 정적 메서드는 형의 인수를 전달받는 제네릭 메서드입니다.
where T: TextProcessor는 형 T가TextProcessor이거나 TextProcesor를 상속한 서브 클래스
그 뒤에 있는 new()는 형 T가 인수를 가지지 않는 생성자로 인스터스를 생성할 수 있다는 것을 나타냅니다. 이  Run 메서드 안에서는 형 인수 T의 인스턴스를 생성하고 Process 메서드를 호출합니다.

Process 메서드에서는 Initialize, Execute, Terminate 라는 세 개의 메서드를 호출합니다.
이 부분이 다형성을 활용한 부분입니다.
소스코드 상에서는 자기 자신(TextProcessor 클래스)에게 있는 메서드를 호출하지만 실제로 동작할 때는 생성된 인스턴스에 있는 메서드가 호출됩니다.
다형성의 본질인 '다른형을 동일시한다' 라는 개념이 여기에 적용된 것입니다.

Initialize, Execute, Terminate라는 세 개의 메서드는 protected virtual로 지정돼 있으므로
서브클래스에서 오버라이드해서 구체적인 처리를 구현합니다. 아무런 작업도 하지 않아도 된다면 오버라이드하지 않아도 됩니다.




TextProcessor을 이용한 응용 프로그램

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TextFilePorcessor;



namespace LineCounter
{
    class Program:MonoBehaviour {


        private void Start()
        {
            TextProcessor.Run<LineCounterProcessor>("fff");
        }
    }
}

public class LineCounterProcessor:TextProcessor  {
    private int _count;

    protected override void Initialize(string fname)
    {
        //base.Initialize(fname);

        _count = 0;
    }
    protected override void Execute(string line)
    {
        //base.Execute(line);

        _count++;
    }
    protected override void Terminate()
    {
        //base.Terminate();
        Debug.Log(_count + "줄");
    }


}

이 콘솔 응용 프로그램 프로젝트의 소스에서는 LineCounterProcessor 클래스에 Initialize, Execute, Terminate라는 세 개의 메서드를 정의했는데 이 메서드를 호출하는 코드는 존재하지 않습니다.
이 메서드를 호출하는 것은 클래스 라이브러리 쪽에 있는 TextFileProcessor 클래스입니다.

여기서는 부모 클래스(TextProcessor)에서 코드의 틀(템플릿)을 마련하고 서브 클래스(LineCounterProcessor)에서 부모 클래스에 있는 메서드를 오버라이드해서 서브 클래스 고유의 기능을 구현했습니다. 이런 패턴을 템플릿 메서드 패턴이라고 합니다. 템플릿 메서드 패턴을 이용하면 서브클래스를 정의하기만 하면 되고 전체적인 처리의 흐름을 작성할 필요가 없기 때문에 '닯았지만 조금 다른 코드'가 양산되지 않게 됩니다.

















댓글 없음:

댓글 쓰기

git rejected error(feat. cherry-pick)

 문제 아무 생각 없이 pull을 받지않고 로컬에서 작업! 커밋, 푸시 진행을 해버렷다. push에선 remote와 다르니 당연히 pull을 진행해라고 하지만 로컬에서 작업한 내용을 백업하지 않고 진행하기에는 부담스럽다(로컬작업 유실 가능성) 해결하려...