Design Pattern

Template Method

sseram 2022. 9. 6. 20:16
반응형

Template Method
정의 : 템플릿 메소드 패턴(template method pattern)은 소프트웨어 공학에서 동작 상의 알고리즘의 프로그램 뼈대를 정의하는 행위 디자인 패턴이다.[1] 알고리즘의 구조를 변경하지 않고 알고리즘의 특정 단계들을 다시 정의할 수 있게 해준다
전체 ㅡ 부분의 관계를 가지는 객체들 사이의 관계를 정의할 때 유용하다
   

 핵심 : 변하는 코드와 변하지 않는 코드를 분리하라. 
변하는 코드를 가상 함수를 통하여 분리한다 : template method
변하는 코드를 class 를 통하여 분리한다 : strategy pattern
(C++)  변하는 코드를 class의 template을 통하여 분리한다 : Policy Based class




Template Method 예제 코드 :


#include <iostream>
#include <string>

using namespace std;

class InputBox {
private:
    string data;
public:
    string getData() {
        cin >> data;
        return data;
    }
};

int main() {
    InputBox input;

    string data = input.getData();

    cout << "User Input Data : [" << data << "]" << endl;
}



위와 같이 inputBox라는 user로부터 data를 입력받을 수 있게 하는 간단한 예제를 만들어 보았다.

만약 user에게 데이터를 입력 받을 때, 숫자만 입력받게 정책을 만들고 싶다면 어떻게 해야 할까?




#include <iostream>
#include <string>

using namespace std;

class InputBox {
private:
    string data;
    bool isdigit(const string& data) {
        for (const char& ch : data) {
            if (ch< '0' || ch > '9') return false;
        }
        return true;
    }
public:
    string getData() {
        while (true) {
            cin >> data;
            if (isdigit(data)) break;
            else {
                cout << "정책에 맞지 않는 문자가 있습니다!" << endl;
            }
        }

        return data;
    }
};

int main() {
    InputBox Digitinput;

    string data = Digitinput.getData();

    cout << "User Input Data : [" << data << "]" << endl;
}



이런 식으로 getData 중간에 digit인지 아닌지를 판단하는 조건문을 추가해주면 될 것이다.



만약 반대로 숫자를 입력받지 않고 알파벳 소문자만 받는 inputbox를 만들려면 어떻게 해야할까?

또는 , 특수문자를 입력받지 않는 inputbox를 만들려면 어떻게 해야할까?







여기서 위 개요에서 나온 핵심인 [변하는 코드와 변하지 않는 코드를 분리하라] 를 사용해야 한다.



위 코드에서 변하는 코드와 변하지 않는 코드는 무엇일까?



inputbox이므로 밖에서 사용받는 getData()의 원형과 안에서 하는 일은 변하지 않을 것이다.

다만 getData 내부에서 data가 숫자인지 판단하는 isdigit 함수는 때에 따라서 변하게 될 것이다. 그러니 getData는 그대로 놔두고, 변하는 부분인 isdigit 함수 부분을 밖으로 빼야 할 것이다.







변하는 코드를 가상 함수를 통하여 분리한다 : template method
변하는 코드를 class 를 통하여 분리한다 : strategy pattern
(C++)  변하는 코드를 class의 template을 통하여 분리한다 : Policy Based class


위 개요를 보면, template method pattern에서는 변하는 코드를 가상 함수를 통하여 분리한다고 한다. 이를 통해 isdigit 가상 함수로 분리하고, 좀 더 common한 경우에 사용할 수 있도록 함수 이름을 변경해 보자.




#include <iostream>
#include <string>

using namespace std;

class InputBox {
private:
    string data;
protected:
    virtual bool isValid(const string & data) = 0;
public:
    string getData() {
        while (true) {
            cin >> data;
            if (isValid(data)) break;
            else {
                cout << "정책에 맞지 않는 문자가 있습니다!" << endl;
            }
        }

        return data;
    }
};

class DigitInputBox : public InputBox {
    virtual bool isValid(const string & data) override {
        for (const char& ch : data) {
            if (ch< '0' || ch > '9') return false;
        }
        return true;
    }
};

int main() {
    DigitInputBox Digitinput;

    string data = Digitinput.getData();

    cout << "User Input Data : [" << data << "]" << endl;
}



이런 식으로 변하지 않는 부분은 InputBox에 그대로 두고,

변하는 IsValid 부분은 가상 함수로 만들어서 따로 구현하게 만들었다.

만약 숫자를 입력받는 inputbox가 아니라 알파벳 소문자만을 입력받는 inputBox를 만들고 싶다면, 소문자만을 valid한 것으로 취급하는 새로운 class를 만들어 사용하면 될 것이다.


#include <iostream>
#include <string>

using namespace std;

class InputBox {
private:
    string data;
protected:
    virtual bool isValid(const string & data) = 0;
public:
    string getData() {
        while (true) {
            cin >> data;
            if (isValid(data)) break;
            else {
                cout << "정책에 맞지 않는 문자가 있습니다!" << endl;
            }
        }

        return data;
    }
};

class DigitInputBox : public InputBox {
    virtual bool isValid(const string & data) override {
        for (const char& ch : data) {
            if (ch< '0' || ch > '9') return false;
        }
        return true;
    }
};

class smallLetterInputBox : public InputBox {
    virtual bool isValid(const string & data) override {
        for (const char& ch : data) {
            if (ch< 'a' || ch > 'z') return false;
        }
        return true;
    }
};

int main() {
    DigitInputBox Digitinput;

    string data = Digitinput.getData();

    cout << "User Input Data : [" << data << "]" << endl;


    smallLetterInputBox stringInput;

    string alphadata = stringInput.getData();

    cout << "User Input Data : [" << alphadata << "]" << endl;

}
반응형

'Design Pattern' 카테고리의 다른 글

flyweight pattern  (0) 2022.12.01
iterator pattern  (0) 2022.11.20
Observer Pattern  (0) 2022.08.14
Decorator pattern  (0) 2022.07.26
factory method  (0) 2022.06.07