LoginSignup
3
1

More than 5 years have passed since last update.

C++によるデザインパターン(TemplateMethodパターン)編

Last updated at Posted at 2018-11-15

はじめに

現在、デザインパターンを学習するために、デザインパターンの本として評価が高い「増補改訂版Java言語で学ぶデザインパターン入門」を読んでいます。ただ文字通り、この本のデザインパターンはJavaで書かれているので、C++を主に使う自分の学習のためにこの本の中のJavaのコードをC++に書き換えてみました。元のJavaのコードはここからダウンロードできます。今回は、TemplateMethodのC++版のコードを書いてみました。(2018/11/21 AbstractDisplay のデストラクタでメモリリークが起こるバグを修正)

TemplateMethodとは

TemplateMethodとは、似たような機能のクラスをまとめて、スーパークラスで処理の流れを決定するパターンです。例えるなら、パワポのテンプレート機能は、同じスライドを作成するという作業は共通しており、各テンプレートは微妙にそれぞれのデザインが違うということに似ていると思います。

CharDisplayクラス

本当はコンストラクタの引数の型をcharにするべきですが、めんどくさいし、本質は変わらないのでstd::stringにしています。ようするに手抜きです。きちんとchar型で動くように修正しました。

CharDisplay.cpp
#include"CharDisplay.h"

CharDisplay::CharDisplay(const char *ch) : ch(ch){}


void CharDisplay::open() {
    std::cout << "<<" ;
}

void CharDisplay::print() {
    std::cout << ch;
}

void CharDisplay::close() {
    std::cout << ">>" << std::endl;
}
CharDisplay.h
#pragma once
#include"AbstractDisplay.h"

class CharDisplay : public AbstractDisplay {
private:
    const char *ch;

public:
    CharDisplay(const char *ch);
    void open();
    void print();
    void close();
};

StringDisplayクラス

StringDisplay.cpp
#include"StringDisplay.h"

StringDisplay::StringDisplay(std::string string) :string(string), width(string.size()) {}

void StringDisplay::open()
{
    printLine();
}

void StringDisplay::print()
{
    std::cout << "|" + string + "|" << std::endl;
}

void StringDisplay::close()
{
    printLine();
}

void StringDisplay::printLine()
{
    std::cout << "+";

    for (int i = 0; i < width; i++) {
        std::cout << "-";
    }
    std::cout << "+" << std::endl;
}
StringDisplay.h
#pragma once
#include"AbstractDisplay.h"
#include<string>

class CharDisplay : public AbstractDisplay {
private:
    std::string ch;

public:
    CharDisplay(std::string Newch);
    void open();
    void print();
    void close();
};

AbstractDisplayクラス(main関数も含む)

ここでは、Javaのガベージコレクションを再現するために、unique_ptrを使用しました。また、Javaの元コードにfinalが使われているので、ここでもC++11から追加されたfinalを使用しています。

AbstractDisplay.cpp
#include"AbstractDisplay.h"
#include"StringDisplay.h"
#include"CharDisplay.h"

void AbstractDisplay::display()
 {
    open();
    for (int i = 0; i < 5; i++) {
        print();
    }
    close();
}

int main() {
    std::unique_ptr<AbstractDisplay> d1(new CharDisplay("H"));
    std::unique_ptr<AbstractDisplay> d2(new StringDisplay("hello world"));
    std::unique_ptr<AbstractDisplay> d3(new StringDisplay("こんにちは"));

    d1->display();
    d2->display();
    d3->display();

}
AbstractDisplay.h
#pragma once
#include<iostream>
#include<string>
#include<memory>

class AbstractDisplay {
public:
  virtual ~AbstractDisplay() {};
    virtual void open() = 0;
    virtual void print() = 0;
    virtual void close() = 0;
    virtual void display() final;
};

最後に

本記事では元コードのC++の書き換えに重点を置いたためにデザインパターン自体の説明は端折っています。デザインパターンや元コードの解説について詳しく知りたい場合は元コードが載っている「増補改訂版Java言語で学ぶデザインパターン入門」をおすすめします。本記事がデザインパターンで悩むC++学習者の手助けになれば幸いです。

3
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1