としおの読書生活

田舎に住む社会人の読書記録を綴ります。 主に小説や新書の内容紹介と感想を書きます。 読書の他にもワイン、紅茶、パソコン関係などの趣味を詰め込んだブログにしたいです。

3884509_s

研究者であり日本のライフハックの先駆者である、堀正岳さんの『ライフハック大全ー人生と仕事を変える小さな習慣250』を読みました。

その中で個人的にすぐに真似してみたいと思ったライフハックを7つ紹介していきます。




作業を「下り坂」でパーキングする


毎日の作業をいつもきりの良いところで終わらせようとする人は多いのではないのでしょうか。

これは気分が良いことかもしれませんが、明日以降にも引き続き同じ作業を続ける場合は、注意が必要です。

次の日に新しいタスクを始めようとすると気が重くなかなか手がつかないことがあります。

この問題を解決するために、1日の作業をあえて中途半端なところで切り上げましょう

こうすることで、次の日に作業を気持ちよく始めることができます。

また下り坂でやめることで、ダラダラときりの良いところまで残業しようとする、無駄な残業時間も減らすことができます。



48:12時間分割法


どんなにすごい人でも一日に集中することができる時間は限られています。

そこで、集中力をマラソンランナーのように長い時間維持するテクニックを教えます。

そのテクニックは48:12時間分割法です。

これは名前のままで1時間の作業時間を48分の集中時間と12分の休息時間に分けるという方法です。

48分集中した後に12分休息をとることで、次の1時間のサイクルを始めるときに集中力を回復させることができます。

このテクニックを使う上で大切なことは、調子がよくても休息するときと作業を行う時間をしっかりと分けることです。

その時は、調子がいいかもしれませんが無理をしているだけにすぎないのでいずれ集中力が途切れるでしょう。

また、48分と12分という時間配分はあくまで例です。人によっては50分作業して10分休憩や、30分作業して10分休憩などバランスが違います。

自分に最適な時間を見つけましょう。



怒りを制御するための3つのテクニック


いくら怒らないようにしていても予想外の出来事なので怒りを覚えることがあります。

ここでは、怒りを抑えるための3つのテクニックを紹介していきます。


1. 怒りそうになったら手のひらをパーにする

怒りを感じると緊張して握り拳を作りがちですが、これを意識的にパーにすることで緊張が和らぎます。


2. 肩を下げる

手のひらと同様に怒っている時は、緊張して肩が上がりがちです。

意識して肩を下げるようにしてリラックスの姿勢をとりましょう。


3. 話すスピードを落とす

怒りが、込み上げると早口になりがちです。意識的にゆっくりと話すようにしましょう。

ゆっくりと話すことで、話し声も小さくなり冷静さを取り戻すことができます。






大量の悪いアイデアをつくる


優秀な人でも大量の良いアイデアを生み出すのは難しいです。

一方、大量の悪いアイデアを生み出すことはそこまで難しくありません。

実は悪いアイデアを生み出すというのは、良いアイデアを生み出すための鍵です。

毎朝5つのアイデアを書き留める習慣を作りましょう。

毎朝考えていると、ひどいアイデアも大量に生まれます。しかし、こうして様々なアイデアを組み合わせていくことで誰にも辿り着かない発想に行き着くことがあるでしょう。

あのエジソンですら、アイデアを生み出す量に拘っていたのですからきっとあなたも大量のアイデアを生み出せばいつか良いものが見つかるでしょう。



利き手と逆の手を使ってマインドフルネスを体感する


マインドフルネスとは、現在起こっていることに意識を集中させる瞑想法で、ストレスを軽減することや様々な心理的な症状に効果があることが知られています。

しかし、瞑想ができるようになるためには練習が必要です。

そこで、普段利き手として使っている腕とは逆の腕で、日常の活動を行ってみましょう

利き腕と違う手を使うことで、掃除をするだけでも全てを意識的に注意深く行わなければうまくできません。

利き手では自動化していた行動を集中して行うことでマインドフルネスに近い精神状態を生み出すことができます。

マインドフルネスの状態を体感して心の健康を守りましょう。



習慣のトリガーとして優秀なのは「時間」と「場所」


新しい習慣を定着させるときに大切なことは、毎日必ず発生するものをトリガーに設定し、その流れで実行する行動だけを入れ替えるという作戦です。

例えば夕食終わりに必ずテレビをつけるという習慣があるとします。

この流れを脱線させて別の行動をとることで新しい習慣をつくることができます。

夕食後に毎日風呂掃除をするようにすると次第にテレビをつける習慣が風呂掃除をする習慣へと変化していくでしょう。

こうしたトリガーをきっかけに新しい習慣をつくるようにしましょう。



「30日チャレンジ」で人生を楽しくかえてゆく


みなさん新しいことを初めてみたいけどなかなか始めることができないと困っていませんか?

そこで「30日チャレンジ」をしてみましょう。

「30日チャレンジ」とは人生でずっとやってみたかったことを、次の30日間だけ生活に取り入れてみることです。

30日という数字が良い数字で、30日あればちょうど新しい習慣を身につけることができ、「30日チャレンジ」の後も継続的に行うことができます。

一方ずっとやってみたかったことでも、30日すら続けることができなければそれはそこで辞めてしまっても良いことです。

とりあえず30日だけと思って新しいことをやってみましょう。



まとめ


『ライフハック大全ー人生と仕事を変える小さな習慣250』では上記で紹介した他にも様々なライフハックが紹介されています。

本書の後書きでも書かれていたのですが、ライフハックは全て真似しないといけないわけではありません。

自分が真似したいと思うライフハックだけを取り出して、実践していき自分の生活を少しでも良いものにしていきましょう。






3753817_s


以前、以下の記事で作成したSingletonパターンがスレッドセーフではなかったため、本記事ではスレッドセーフなSingletonパターンを実装していきます。





Singletonパターンのクラス構成


今回作成する、スレッドセーフなSingletonパターンのクラス構成は以下のとおりです。

SingletonThreadSafe


Singletonパターンを実装する場合、インスタンスの作成をgetInstanceメソッドで行うということをしがちですが、この場合複数個のスレッドから同時に呼ばれたときに別のインスタンスが作成されるという問題がありました。

そこで今回は新たにcreateメソッドを実装して、ここでインスタンスを作成することでスレッドセーフなSingletonパターンを作成します。

また新しくインスタンスを破棄するdestroyメソッドも追加しました。





C++による実装


サンプルとして複数のスレッドからgetInstanceメソッドを呼ばれても一つしかインスタンスを作成しないということを証明するプログラムを作成します。


Singletonクラス



ヘッダファイル

#ifndef H_SINGLETON
#define H_SINGLETON

class Singleton{
private:
    Singleton();
    ~Singleton();

public:
    static void create();
    static void destroy();
    static Singleton* getInstance();

private:
    static Singletonm_singleton;
};
#endif // H_SINGLETON


ソースファイル

#include <iostream>
#include "Singleton.h"

SingletonSingleton::m_singleton = nullptr;

Singleton::Singleton()
{
    std::cout << "インスタンスを生成しました" << std::endl;
}

Singleton::~Singleton(){
    std::cout << "インスタンスを削除しました" << std::endl;
}

void Singleton::create(){
    if (!m_singleton){
        m_singleton = new Singleton();
    }
}

void Singleton::destroy(){
    if (m_singleton){
        delete m_singleton;
        m_singleton = nullptr;
    }
}

Singleton* Singleton::getInstance(){
    if (!m_singleton){
        return m_singleton;
    }
    return nullptr;
}



main関数


上記で作成したSingletonクラスを実際に使用してみます。

今回Windows環境で作成したため、スレッドはWin32 APIを使用して作成しています。


ソースファイル

#include <iostream>
#include <windows.h>
#include "Singleton.h"

#define LOOP 10
#define THREADNUM 10

struct stThreadArg{
    unsigned long threadNum;
};

DWORD WINAPI thread(LPVOID *arg){
    //struct stThreadArg* threadArg = (struct stThreadArg*)arg;
    unsigned longthreadArg = (unsigned long*)arg;
    std::cout << "Start thread" << *threadArg << std::endl;
    for(int i=0i<LOOP; ++i){
        Singleton::getInstance();
    }
    std::cout << "End thread" << *threadArg << std::endl;
    return 0;
}


int main(void){
    std::cout << "Start" << std::endl;
    
    // インスタンスを作成
    Singleton::create();
    
    /* スレッドの生成 */
    HANDLE handle[THREADNUM];
    unsigned long threadArg[THREADNUM];
    for (int i=0i<THREADNUM; ++i){
        threadArg[i] = i;
        handle[i] = CreateThread(00, (LPTHREAD_START_ROUTINEthread, &threadArg[i], 0NULL);
    }
    WaitForMultipleObjects(THREADNUMhandle,TRUEINFINITE);

    // インスタンスを削除
    Singleton::destroy();
    
    std::cout << "End" << std::endl;

    return 0;
}


実行結果

Start
インスタンスを生成しました
Start threadStart thread2
End thread2
Start thread9
End thread9
Start thread4
End thread4
Start thread3
End thread3
Start thread7
End thread7
Start thread8
End thread8
0
End thread0
Start thread6
End thread6
Start thread5
End thread5
Start thread1
End thread1
インスタンスを削除しました
End


実行結果からインスタンスの生成がcreateメソッドを呼んだときしか行っていないことが分かりますね。

また、destroyメソッドによってインスタンスの削除もしっかり行われています。



まとめ


Singletonパターンを作成するときは、スレッドセーフではない実装を行うようにしましょう。

もし仮にスレッドセーフではないSingletonパターンを作成したとして、不具合が起きていない場合、それはたまたま不具合が起きなかっただけにすぎません。

できる限り不具合が発生する要因をなくしていきましょう。







3753817_s

本記事では、デザインパターンの名著である結城浩さんの『Javaで学ぶデザインパターン入門』を参考にSingletonパターンをC++で実装していきます。



Singletonパターンとは


プログラムを作成するとき、同じクラスのインスタンスを複数作成することがあります。

しかし、中にはこのクラスのインスタンスは、たった1つしか作らないし、作りたくないというものも存在します。

注意深くプログラムを作成してインスタンスを1つしか作らないという方法もありますが、これはかなり手間のかかる作業です。

プログラマが注意してインスタンスが1個しか生成されないプログラムをつくるのではなく、

  • 指定したクラスのインスタンスが絶対に1個しか存在しないことを保証したい
  • インスタンスが1個しか存在しないことをプログラム上で表現したい

場合には、どうしたらよいでしょうか。

この問題を解決するために、インスタンスが1個しか存在しないことを保証するパターンをSingletonパターンと呼びます。



Singletonパターンの登場人物


Singletonパターンは以下のようなクラス構成になっています。

Singleton


Singleton


Singletonパターンには、Singletonクラスしか登場しません。

Singletonクラスの役割はインスタンスが複数個できないようにstatic変数でインスタンスを持ち、getInstanceメソッドでインスタンスを返します。

getInstanceメソッドは、何度呼ばれても同じインスタンスしか返さないという特徴があります。



C++による実装


サンプルとしてSingletonパターンを使用すると一つしかインスタンスを作成しないということを証明するプログラムを作成します。

クラス構成は以下の通りです。


Singleton


Singletonクラス


外部からnewできないようにコンストラクタとデストラクタがpirvateになっているのが特徴です。


ヘッダファイル

class Singleton{
private:
    Singleton();
    ~Singleton();

public:
    static Singleton* getInstance();

private:
    static Singletonm_singleton;
};


ソースファイル

#include <iostream>
#include "Singleton.h"

SingletonSingleton::m_singleton = nullptr;

Singleton::Singleton()
{
    std::cout << "インスタンスを生成しました" << std::endl;
}

Singleton::~Singleton(){
}

Singleton* Singleton::getInstance(){
    if (!m_singleton){
        m_singleton = new Singleton();
    }
    return m_singleton;
}



main関数


上記で作成したSingletonクラスを実際に使用してみます。


ソースファイル

#include <iostream>
#include "Singleton.h"

SingletonSingleton::m_singleton = nullptr;

Singleton::Singleton()
{
    std::cout << "インスタンスを生成しました" << std::endl;
}

Singleton::~Singleton(){
}

Singleton* Singleton::getInstance(){
    if (!m_singleton){
        m_singleton = new Singleton();
    }
    return m_singleton;
}


実行結果

Start
インスタンスを生成しました
obj1とobj2は同じインスタンスです。
End

実行結果からコンストラクタが一度しか呼ばれていないこと、obj1とobj2が同じインスタンスであることが分かりますね。



まとめ


今回は、Singletonパターンを実装していきました。

一つしかインスタンスを作成したいときに便利なクラスです。

ちなみに上記の実装はスレッドセーフではないため、最近のSingletonパターンではインスタンスを作成するCreateメソッドやインスタンスを削除するDestoryメソッドなどを作成してスレッドセーフを保証したりもしています。

スレッドセーフなSingletonパターンを以下の記事で作ってみました。




Singletonパターンは、すごく便利ですがglobal関数的な使い方もできるため試験が行いにくくなるという欠点もあります。

使いどころを考えて使用していきましょう。






3753817_s

C++の実行時間を計測するときにWindowsだとどうしたらいいのか迷うことが多かったので、精度別の実行時間の計測方法をまとめていきます。



clock(10ミリ秒程度)


clockはC言語でも使用できる標準形の関数で、プログラム実行開始からの経過時間をミリ秒単位で返します。

精度は処理系に依存しますが、Windowsでは10ミリ秒程度です。

C言語の標準ライブラリに含まれる関数なのでWindows以外でも使える点が嬉しいです。

以下は、実行時間計測のサンプルプログラムです。

#include <iostream>
#include <vector>
#include <time.h>

using namespace std;

int main(void){    
    clock_t start = clock();

    // 計測対象(今回はvectorに1000000個要素を追加する)
    vector<inttestVec;
    for (int i=0i<1000000; ++i){
        testVec.push_back(i);
    }
    clock_t end = clock();

    cout << end-start << endl;


    return 0;
}



timeGetTime(1ミリ秒)


timeGetTimeはWin32 APIで用意されている関数で、システム起動開始からの経過時間をミリ秒単位で返します。

精度は1ミリ秒程度です。

timeGetTimeを使用するためには、windows.hのインクルードと、winmm.libのリンクが必要です。

以下は、実行時間計測のサンプルプログラムです。

#include <iostream>
#include <vector>
#include <windows.h>

using namespace std;

int main(void){    
    DWORD start = timeGetTime();

    // 計測対象(今回はvectorに1000000個要素を追加する)
    vector<inttestVec;
    for (int i=0i<1000000; ++i){
        testVec.push_back(i);
    }
    DWORD end = timeGetTime();

    cout << end-start << endl;


    return 0;
}






QueryPerformanceCounter(マイクロ秒)


こちらもtimeGetTimeと同様にWin32 APIで用意されている関数です。

精度は環境に依存しますが、マイクロ秒~10ナノ秒程度で、Windowsで使える時間計測の方法で最も精度が高いです。

しかし、実行時間の計測開始前にQueryPerformanceFrequency関数でカウントアップする周波数を取得するなど少し他のAPIに比べて手間がかかるという欠点もあります。

以下は、実行時間計測のサンプルプログラムです。

#include <iostream>
#include <vector>
#include <windows.h>

using namespace std;

int main(void){    
    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);

    LARGE_INTEGER start;
    QueryPerformanceCounter(&start);

    // 計測対象(今回はvectorに1000000個要素を追加する)
    vector<inttestVec;
    for (int i=0i<1000000; ++i){
        testVec.push_back(i);
    }
    
    LARGE_INTEGER end;
    QueryPerformanceCounter(&end);

    cout << (double)(end.QuadPart - start.QuadPart) / frequency.QuadPart << endl

    return 0;
}



まとめ


今回はWindows環境でC++の実行時間を計測する方法をまとめました。

Linuxと違ってナノ秒単位で正確に計測することはできませんが、QueryPerformanceCounterを使えばかなり正確に実行時間が計測できることが分かりました。

他にも良い計測方法があればコメントで教えていただけますと幸いです。



3753817_s


C++でvectorに対してループを行う方法が色々あります。

今回は、どの書き方が一番効率が良いのかが気になったので調べてみました。




カウンタ方式


カウンタ変数を用意して、データにアクセスする方式。

今回時間の計測は、windows APIのQueryPerformanceCounterを使用して計測します。

「計測対象」とコメントで書かれている部分のループが実行時間の計測対象になります。
カウンタ方式以外では計測対象以外の部分のコードは省略します。

#include <iostream>
#include <vector>
#include <windows.h>

#define LOOPNUM 1000000
using namespace std;

int main(void){
    vector<inttestVec;
    for(int i=0i<LOOPNUM; ++i){
        testVec.push_back(i);
    }

    LARGE_INTEGER frequency;
    QueryPerformanceFrequency(&frequency);

    LARGE_INTEGER start;
    QueryPerformanceCounter(&start);

    // 計測対象
    for(int i=0i<testVec.size(); ++i){
        int a = testVec[i];
    }

    LARGE_INTEGER end;
    QueryPerformanceCounter(&end);

    DWORD end_tm = timeGetTime();
    std::cout << (double)(end.QuadPart - start.QuadPart) / frequency.QuadPart * 1000000 << std::endl

    return 0;
}



イテレータ方式


C++のコンテナクラスのイテレータを使用してデータにアクセスする方式。

for(auto itr=testVec.begin(); itr!=testVec.end(); ++itr){
    int a = *itr;
};



範囲ベース方式


範囲ベース方式は、C++ 11で追加されたコンテナオブジェクトの範囲分ループを行うという方式。

for(intvec : testVec){
    int a = vec;
}



for_each


for_eachは範囲内の全てのイテレータに特定の関数を適用させるときに使用する方法。

void substitute(int x){
    int a = x;
}

for_each(testVec.begin(), testVec.end(), substitute);






実行時間計測結果


今回は、最適化なしと最適化ありでそれぞれ10回ずつ計測して、平均値を実行時間とします。

vectorのサイズは1000000、実行時間の単位はμs(マイクロ秒)です。

実行時間(μs)
カウンタ方式2400.42
イテレータ方式7285.76
範囲ベース方式5402.42
for_each66284.8


最適化なしだとカウンタ方式が最速ということになりました。

余談になりますが、最適化オプション最高(-Ofast オプション)でコンパイルして、実行してみたところ全ての実行時間が0.1μs未満になり正確に計測できませんでした。

最適化オプション込みで実行時間を比較するにはどうすればよかったのだろうか…。



まとめ


今回はvectorのループの実行時間を計測していきました。

最適化オプションなしでの計測になってしまいましたが、Debug環境ではカウンタ方式が最速みたいです。

正直イテレータとかの方が早いのかなと思っていたので意外な結果になりました。



3753817_s


本記事では、デザインパターンの名著である結城浩さんの『Javaで学ぶデザインパターン入門』を参考にFactory Method(ファクトリ・メソッド)をC++で実装していきます。




Factory Methodとは


Factory Methodとは、Template Methodをインスタンス生成の場面に適用したものです。

Factoryは、工場という意味です。

要するにFactory Methodとは、インスタンスを生成するための工場のようなデザインパターンだと思ってください。






Factory Methodの登場人物


Factory Methodは以下のようなクラス構成になっています。


factoryMethod


Product


Factory Methodで生成されるインスタンスが持つべきAPIを定義する抽象クラスです。

APIの具体的な実装は、ConcreateProductでクラスで行います。


Creator


Productを生成する抽象クラスです。

Crateorクラスは、Createメソッドで実際に生成する、ConcreteProductについては何も知りませんが、インスタンスを生成するメソッドを作ることでこの問題を解決しています。


ConcreteProduct


ConcreteProductは実際に生成される具体的な製品の役です。


ConcreteCreator


ConcreteCreatorは実際にConcreteProductを生成する役です。



C++による実装


今回は、IDカードを製造する工場というイメージでプログラムをFactory Methodを使用して実装していきます。

クラス構成は以下の通りです。


factoryMethodSample



Productクラス


Productクラスは抽象クラスとして実装していきます。


ヘッダファイル

#ifndef PRODUCT_H
#define PRODUCT_H

class Product{
public:
    virtual void use()=0;
};
#endif // PRODUCT_H



Factoryクラス


createメソッドでは、インスタンスを生成するcreateProductMethodを呼び出し、生成したインスタンスをregisterProductで登録するという処理を行います。

createメソッド以外の具体的な実装は子クラスで行います。今回の場合は、IDCardFactoryクラスが子クラスにあたります。

createMethodは継承先でオーバーライドされないようにfinalを使って宣言します。

ヘッダファイル

#ifndef FACTORY_H
#define FACTORY_H

#include <iostream>

class Product;

class Factory{
public:
    virtual Product* create(std::string ownerfinal;
    virtual Product* createProduct(std::string owner)=0;
    virtual void registerProduct(Product* product)=0;
};
#endif // FACTORY_H


ソースファイル

#include "Factory.h"
#include "Product.h"

Product* Factory::create(std::string owner){
    Productp = createProduct(owner);
    registerProduct(p);
    return p;
}






IDCardクラス


IDCardクラスはProductクラスを継承して作る、具体的な製品のクラスです。

今回は、useメソッドでカードを使い、getOwnerメソッドでカードの持ち主の名前を返します。

ヘッダファイル

#ifndef IDCARD_H
#define IDCARD_H

#include <iostream>
#include "Product.h"

class IDCard : public Product{
public:
    IDCard(std::string owner);
    ~IDCard();
    void use() final;
    std::string getOwner();
    
private:
    std::string m_owner;
};
#endif // IDCARD_H


ソースファイル

#include <iostream>
#include "IDCard.h"

IDCard::IDCard(std::string owner)
m_owner(owner)
{
    std::cout << owner << "のカードを作ります。" << std::endl;
};

IDCard::~IDCard(){};

void IDCard::use(){
    std::cout << m_owner << "のカードを使います。" << std::endl;
}

std::string IDCard::getOwner(){
    return m_owner;
}



IDCardFactoryクラス


IDCardFactoryクラスではcreateProductメソッドの具体的な実装を行っています。

このメソッドではIDCardのインスタンスを生成します。

また、registerOwnerでは生成したインスタンスを登録します。

ヘッダファイル

#ifndef IDCARDFACTORY_H
#define IDCARDFACTORY_H

#include <iostream>
#include <list>
#include "Factory.h"

class Product;

class IDCardFactory : public Factory{
public:
    IDCardFactory();
    ~IDCardFactory();
    Product* createProduct(std::string owner);
    void registerProduct(Product* product);
    std::list<std::stringgetOwners();
    
private:
    std::list<std::stringm_owners;
};
#endif // IDCARD_H


ソースファイル

#include "IDCardFactory.h"
#include "Product.h"
#include "IDCard.h"

IDCardFactory::IDCardFactory(){};

IDCardFactory::~IDCardFactory(){};

Product* IDCardFactory::createProduct(std::string owner){
    return new IDCard(owner);
}

void IDCardFactory::registerProduct(Product* product){
    m_owners.push_back(dynamic_cast<IDCard*>(product)->getOwner());
}

std::list<std::stringIDCardFactory::getOwners(){
    return m_owners;
}



main関数


今まで作成してきたクラスを実際に使っていきます。

ソースファイル

#include "Factory.h"
#include "Product.h"
#include "IDCardFactory.h"
#include "IDCard.h"

int main(void){
    Factory *factory = new IDCardFactory();
    Product *card1 = factory->create("としお");
    Product *card2 = factory->create("ひろし");
    Product *card3 = factory->create("花子");
    card1->use();
    card2->use();
    card3->use();

    return 0;
}


実行結果

としおのカードを作ります。
ひろしのカードを作ります。
花子のカードを作ります。  
としおのカードを使います。
ひろしのカードを使います。
花子のカードを使います。




まとめ


今回は、Template Methodを応用したFactory MethodはTemplate Methodを実装していきました。

似たようなクラスを複数個生成するときなどに便利なデザインパターンでした。

有効に活用できる場面を分析すれば、とても役にたつのでぜひ使ってみてください。









3753817_s

本記事では、デザインパターンの名著である結城浩さんの『Javaで学ぶデザインパターン入門』を参考にテンプレートメソッド(Template Method)をC++で実装していきます。




テンプレートメソッドとは


テンプレートメソッドとは、テンプレートの機能を持つメソッドが親クラスで定義されており、そのメソッドの中の中小メソッドを子クラスで実装する方法です。

例えばRPGの戦闘をテンプレートメソッドを使って実装するとします。

ここでは戦闘は以下の流れで行うとします。
  1. 移動
  2. 攻撃
移動と攻撃の方法はRPGでいう戦士や魔法使いの役職で変わるとします。

そこで、親クラスで先ほどの戦闘の流れを呼ぶためのテンプレートメソッドと移動と攻撃の抽象メソッドを定義します。

そして、子クラスとして戦士クラスや魔法使いクラスを用意して、移動や攻撃の具体的な実装を行っていきます。


このようにスーパークラスで処理の枠組みを定め、サブクラスでその具体的な内容を定めるデザインパターンをテンプレートメソッドパターン(Template Method)と呼びます。



テンプレートメソッドの登場人物


テンプレートメソッドパターンは以下のようなクラス構成になっています。


テンプレートメソッド



AbstractClass(抽象クラス)


AbstractClass役はテンプレートメソッドを実装します。

また、テンプレートメソッドの他にテンプレートメソッドで使用している抽象メソッドも宣言します。

これらの抽象メソッドの具体的な実装は子クラスであるConcreateClassによって行われます。


ConcreateClass(具象クラス)


AbstractClassで宣言された抽象メソッドを具体的に実装する役です。

ここで実装したメソッドがAbstractClassのテンプレートメソッドにより、呼び出されます。





C++による実装


今回は、文字列や文字を5回表示するといったプログラムをテンプレートメソッドパターンを使用して実装していきます。

クラス構成は以下の通りです。


テンプレートメソッド_sample


AbstractDisplayクラス


今回のサンプルプログラムではAbstractDisplayクラスがテンプレートクラスにあたります。

具体的な実装は、displayメソッドだけ行います。

displayメソッドは、「open → printを5回呼ぶ → close」という流れのメソッドになります。

■ヘッダファイル

#ifndef ABSTRACT_DISPLAY_H
#define ABSTRACT_DISPLAY_H

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


■ソースファイル

#include "AbstractDisplay.h"

void AbstractDisplay::display(){
    open();

    for(int i=0i<5; ++i){
        print();
    }

    close();
}



CharDisplayクラス


CharDisplayクラスの各メソッドは以下のような処理を行います。

メソッド名処理
open文字列"<<"を表示する
printコンストラクタで与えられていた文字を表示する
close文字列">>"を表示する


コンストラクタで'H'という文字列が与えられた場合、AbstractDisplayクラスで定義したdisplayメソッドを呼び出すと、

<<HHHHH>>

のように出力されます。


■ヘッダファイル

#ifndef CHAR_DISPLAY_H
#define CHAR_DISPLAY_H

#include "AbstractDisplay.h"

class CharDisplay : public AbstractDisplay{
public:
    CharDisplay(char ch);
    virtual ~CharDisplay();
    void open() override;
    void print() override;
    void close() override;

private:
    char m_ch;
};
#endif // CHAR_DISPLAY_H


■ソースファイル

#include <iostream>
#include "CharDisplay.h"

CharDisplay::CharDisplay(char ch) : m_ch(ch){}

CharDisplay::~CharDisplay(){};

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

void CharDisplay::print(){
    std::cout << m_ch;
}
 
void CharDisplay::close(){
    std::cout << ">>" << std::endl;



StringDisplayクラス


StringDisplayクラスの各メソッドは以下のような処理を行います。

メソッド名処理
open文字列"+-----+"を表示する
printコンストラクタで与えられていた文字列を"|"と"|"ではさんで表示する
close文字列"+-----+"を表示する


コンストラクタで'Hello'という文字列が与えられた場合、AbstractDisplayクラスで定義したdisplayメソッドを呼び出すと、

+-----+
|Hello|
|Hello|
|Hello|
|Hello|
|Hello|
+-----+

のように出力されます。


■ヘッダファイル

#ifndef STRING_DISPLAY_H
#define STRING_DISPLAY_H

#include <iostream>
#include "AbstractDisplay.h"

class StringDisplay : public AbstractDisplay{
public:    
    StringDisplay(std::string string);
    virtual ~StringDisplay();
    void open() override;
    void print() override;
    void close() override;

private:
    std::string m_string;
};
#endif // STRING_DISPLAY_H


■ソースファイル

#include <iostream>
#include "StringDisplay.h"

StringDisplay::StringDisplay(std::string string) : m_string(string){}

StringDisplay::~StringDisplay(){};

void StringDisplay::open(){
    std::cout << "+";
    for(int i=0im_string.length(); ++i){
        std::cout << "-";
    }
    std::cout << "+" << std::endl;
}

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

void StringDisplay::close(){
    std::cout << "+";
    for(int i=0im_string.length(); ++i){
        std::cout << "-";
    }
    std::cout << "+" << std::endl;



main関数


今まで作成してきたクラスを実際に使っていきます。


■ソースファイル

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

int main(void){
    AbstractDisplay *d1 = new CharDisplay('H');
    AbstractDisplay *d2 = new StringDisplay("Hello, world.");

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

    delete d1;
    delete d2;

    return 0;
}


■出力結果

<<HHHHH>>
+-------------+
|Hello, world.|
|Hello, world.|
|Hello, world.|
|Hello, world.|
|Hello, world.|
+-------------+





まとめ


テンプレートメソッドパターンでは、テンプレートメソッドでアルゴリズムが定義されているため、子クラス側ではアルゴリズムの流れを気にせずに実装することができました。

テンプレートメソッドでアルゴリズムが共通化されているため、仮にアルゴリズムが間違えていたとしてもテンプレートメソッドクラスだけを修正すればよいので、効率的にプログラムを修正することができます。

プログラムで不具合を少なくするためには、同じ処理を何度も書かないということが大切ですので、せひテンプレートメソッドを使用してプログラムの共通化を行っていきましょう。






PXL_20210227_032531375


瀬尾まいこさんの『君が夏を走らせる』を読みました。

たった一ヶ月の短い夏を描いている作品ですが、二歳に満たない鈴香と高校生の大田君の成長を見ることができ、読んでいるだけで癒されるし、ところどころ感動するシーンもある良作でした。

以下、あらすじと感想になります。



『君が夏を走らせる』のあらすじ


中学三年生のころ駅伝に出場して以来、何かに夢中になることの楽しさをしった大田。

高校生になったら不良をやめて堅実に生きようと思っていた矢先、大田は目指していた高校の受験に失敗し、地域の不良が集まる学校に進学することになった。

周りとの温度の違いもあり、大田は徐々に高校から足が遠のいていった。

新しく夢中になることができるものを見つけることができず、日々をやり過ごしていた大田のもとに、中学のときに仲良くしていた先輩から一本の電話が入った。

その電話の内容は、妻が入院することになったので一ヶ月ほど、一歳の娘である鈴香の子守をしてくれないかというものだった。

高校生の自分が人の子守なんてすることができないと思った大田は、先輩からの頼みを断ろうとしたが、断り切れず一か月の子守を引き受けることにした。

子守を初めたはいいが、鈴香は泣き止まないし、ご飯も大人しく食べてくれない。

小さな鈴香に振り回された大田は、振り回されながらも鈴香とともに過ごす時間を幸せに過ごし、徐々に何かに夢中になるということを思いだすことになる。

二度と戻らぬ記憶に温かい、涙あふれるひと夏の奮闘記。



感想(ネタバレあり)


鈴香ちゃんと大田君の成長を描いているとても良い作品でした。

鈴香ちゃんの世話を頼まれたばかりの頃の大田君は、断り切れなくてしかたなく世話をしてあげている感がすごく強かったです。しかし、時間がたつにつれて鈴香ちゃんとともに過ごすことの楽しさを知った大田君を見ていると心がほっかりしました。

二人が仲良くなるにつれて別れの時が少しずつ迫っている様子が切なく感じました。

もちろん鈴香は先輩の娘なので二度と会えなくなるというわけではないのですが、二人で今までのような濃密な時間を過ごすことはもうないんでしょうね…。


大田君の成長


私は『君が夏を走らせる』のテーマは”成長”だと思っています。

一方大田君は、高校受験に失敗してしまい、物語の序盤では自分が成長することはないと感じながら自堕落な生活を送っていて、自分が成長することはできないと思い込んでいるような様子でした。

しかし、鈴香との出会いをきっかけに大田君は、どんな経験からでも人は成長できるということをしります。

  • 大田君が話しているのを聞いて「すげー」という言葉を使えるようになる
  • 大田君のまねをしておもちゃのフライパンで料理をする
  • 大田君が買ってきてくれた積み木で遊ぶ鈴香

鈴香は、まだ二歳なのでどんな些細な経験でもすべてを糧にして成長していきます。
その様は、大田君を通して学習をしているとも言えます。

そんな鈴香の成長を見てきた大田君はラストシーンで以下のように思います。

記憶のどこにも残っちゃいないけれど、俺にも鈴香と同じように、すべてが光り輝いて見えたときがあったのだ。もちろん、今だってすべてが光を失っているわけじゃない。こんなふうに俺に「がんばって」と声を送ってくれるやつがいるのだから。俺はまだ十六歳だ。「もう十分」なんて、言ってる場合じゃない。
『君が夏を走らせる』より

上記の大田君の想いから、大田君が閉じこもっていた殻をやぶって、これからも成長していくだろうということが分かりますね。





子育ての難しさ


大田君が鈴香に苦戦する様子や公園で出会ったママさんたちの様子を見ていると、子育てって大変なんだなと感じました。

それと同時に子育てには、子どもに好きなことをさせてあげることと、親が子どもが学ぶことができる環境を整えてあげることが大切なんだと本作から学びました。

大田君は基本的には鈴香ちゃんのしたいことに対して否定することはなく、適切な遊び方で遊ばせてあげていました。

また、大田君と鈴香ちゃんの様子を見ていると将来自分に子どもができたら、レトルト食品ばかり与えるのではなく、大田君のように子どもが満足するような料理を作ってあげたいなとも感じました。

その他にも鈴香ちゃんは昼食後必ず大田君に買ってきてもらった絵本を読んでもらうのが習慣だという場面がありました。

このシーンを読んで子どもが自ら絵本を読んでもらいだがるような環境を作りが必要だと感じさせられました。

とりあえず、将来子育てをするときは大田君の子育てを参考にすればなかなか良い子が育つような気がしました。



まとめ


『そして、バトンは渡された』を読んだことをきっかけに『君が夏を走らせる』を読みましたがとても面白く大満足でした。

大田君や鈴香のように常に自分は成長することができるということを忘れずに今後の人生を歩んでいきたいです。

余談になりますが、あとがきで、本作には『あと少し、もう少し』という前作があったということを知りました。

こちらでは、中学時代の駅伝のときの大田君の様子などを描いているみたいなので是非読んでみようと思います。






3753817_s


本記事では、デザインパターンの名著である結城浩さんの『Javaで学ぶデザインパターン入門』を参考にアダプターパターン(Adapter)をC++で実装してみました。



アダプターパターン(Adapter)とは


アダプターパターンとは、「すでに提供されているもの」と「必要なもの」の間にある「ずれ」を埋めて再利用するためのデザインパターンです。

提供されたAPIなどを手直しするために使われます。

アダプターパターンには、以下の2種類の実装方法があります。

  • クラスによるAdapterパターン(継承を使ったもの)
  • インスタンスによるAdapterパターン(委譲を使ったもの)



クラスによるAdapterパターン(継承を使ったもの)


継承を使ったアダプターパターンは以下のようなクラス図になります。


アダプターパターン_継承



継承のAdapterパターンは、Adaptee役のメソッドがほぼそのまま使えそうなときに使われます。


Target(対象)


今必要となっているメソッドを定める役で、インタフェースとなっています。

C++では、二重継承を非推奨としているため、継承を使ったアダプターパターンでは、Targetは省略されることが多いです。


Client(依頼者)


Target役(省略する際はAdapter役)のメソッドを使って仕事をする役です。

main関数のようなAPIを呼び出すやつだと思ってもらえば大丈夫です。


Adaptee(適合される側)


すでに用意しているメソッドをもっている役です。要するに使いたいAPIを持っているクラスのことですね。

Target役が使いたいAPIがAdaptee役ですでに実装していたら、Adapter役は必要ないんですけどね…。


Adapter


Adapterパターンの主役です。Adaptee役のメソッドを使用して、Targetが求めているメソッドを作り出すやくですね。



インスタンスによるAdapterパターン(委譲を使ったもの)


委譲を使ったアダプターパターンは以下のようなクラス図になります。


アダプターパターン_委譲


委譲を使ったAdapterパターンは、Adaptee役のメソッドを呼び出す前に手を加えたいことが多い場合に有効です。

Adaptee役のメソッドをそのまま呼び出したい場合は、メソッドを再定義する必要があり、コード量が増えるというデメリットもあります。

C++では多重継承(インタフェースと親クラスの同時継承)が推奨されていないこともあり、委譲を使ったAdapterパターンのほうがよくつかわれるような気がします。



C++で継承をつかったアダプターパターンを実装


今回は、与えられた文字列を

(Hello)
*Hello*

のように表示する簡単なものをAdapterパターンを使用して実装していきます。

クラス構成は以下の通りです。


アダプターパターン_サンプル1



二重継承をしないようにTargetクラスを省略した実装にしています。


Bannerクラス


Bannerクラスは、事前に用意されていたAPIクラスだと思ってください。

■ヘッダファイル

#ifndef BANNER_H
#define BANNER_H

#include <iostream>

class Banner{
public:
    Banner(std::string string);
    
    virtual ~Banner();

    void showWithParen();

    void showWithAster();

private:
    std::string m_string;
};
#endif // BANNER_H


■ソースファイル

#include "Banner.h"

Banner::Banner(std::string string)
m_string(string
{

}

Banner::~Banner(){}

void Banner::showWithParen(){
    std::cout << "(" << m_string << ")" << std::endl;
}

void Banner::showWithAster(){
    std::cout << "*" << m_string << "*" << std::endl;
}



PrintBannerクラス


PrintBannerクラスがアダプターの役目を果たします。

今回はm単純な実装のためBannerクラスのAPIをそのまま呼び出すだけになります。

■ヘッダファイル

#ifndef PRINTBANNER_H
#define PRINTBANNER_H

#include "Banner.h"

class PrintBanner : public Banner{
public:
    PrintBanner(std::string string);

    ~PrintBanner();

    void printWeak();
    
    void printStrong();

};
#endif // PRINTBANNER_H


■ソースファイル

#include "PrintBanner.h"

PrintBanner::PrintBanner(std::string string)
Banner(string)
{

}

PrintBanner::~PrintBanner(){}

void PrintBanner::printWeak(){
    showWithParen();
}

void PrintBanner::printStrong(){
    showWithAster();
}



main関数


ここまで作ってきたAdapter役のPrintBannerクラスを使って、"Adapter Sample"という文字列を括弧付きと*ではさんで表示します。

■ソースファイル

#include "PrintBanner.h"

int main(void){
    PrintBanner printBanner("Adapter Sample");
    
    printBanner.printWeak();
    printBanner.printStrong();

    return 0;
}


■実行結果

(Adapter Sample)
*Adapter Sample*






C++で委譲をつかったアダプターパターンを実装


委譲を使ったアダプターパターンのサンプルプログラムのクラス構成は以下の通りです。


アダプターパターン_サンプル2


Bannerクラス


■ヘッダファイル

#ifndef BANNER_H
#define BANNER_H

#include <iostream>

class Banner{
public:
    Banner(std::string string);
    
    virtual ~Banner();

    void showWithParen();

    void showWithAster();

private:
    std::string m_string;
};
#endif // BANNER_H


■ソースファイル

#include "Banner.h"

Banner::Banner(std::string string)
m_string(string
{

}

Banner::~Banner(){}

void Banner::showWithParen(){
    std::cout << "(" << m_string << ")" << std::endl;
}

void Banner::showWithAster(){
    std::cout << "*" << m_string << "*" << std::endl;
}



Printクラス


JavaでいうインタフェースはC++では抽象クラスとして実装していきます。

■ヘッダファイル

#ifndef PRINT_H
#define PRINT_H

class Print{
protected:
    virtual ~Print(){};

    virtual void printWeak()=0;
    
    virtual void printStrong()=0;
};
#endif // PRINT_H



PrintBannerクラス


■ヘッダファイル

#ifndef PRINTBANNER_H
#define PRINTBANNER_H

#include <iostream>
#include "Print.h"

class Banner;

class PrintBanner : public Print{
public:
    PrintBanner(std::string string);

    virtual ~PrintBanner();

    void printWeak() override;
    
    void printStrong() override;

private:
    Banner *m_Banner;

};
#endif // PRINTBANNER_H



■ソースファイル

#include "PrintBanner.h"
#include "Banner.h"
#include "Print.h"

PrintBanner::PrintBanner(std::string string)
{
    m_Banner = new Banner(string);
}

PrintBanner::~PrintBanner(){
    delete m_Banner;
}

void PrintBanner::printWeak(){
    m_Banner->showWithParen();
}

void PrintBanner::printStrong(){
    m_Banner->showWithAster();
}



main関数


■ソースファイル

#include "PrintBanner.h"

int main(void){
    PrintBanner printBanner("Adapter Sample");
    
    printBanner.printWeak();
    printBanner.printStrong();

    return 0;
}


■実行結果

(Adapter Sample)
*Adapter Sample*




まとめ


個人開発ではなく、会社などで集団で開発する場合は、いきなりAPIの使用が変更することが多々あります。

いきなりの変更でも困らないようにアダプターパターンを使って、修正箇所ができる限り少なくなるようなプログラムを作っていきましょう。







DSC_3832


住野よるさんの『麦本散歩の好きなもの』を読みました。

今までの住野よるさんの作品は学生を主人公とした作品ばかりでしたが、今回は新卒の社会人が主人公となっており、若い人から大人まで楽しめる作品でした。ただ、普段のテイストとは少し異なる作品であるため人によっては物足りなく感じるかもしれません。

本作は図書館勤務の新卒女子、麦本三歩のなにげない日常のショートストーリーが描かれている作品です。

タイトルが『麦本三歩の好きなもの』ということで、各ショートストーリーのタイトルが "麦本三歩は歩くのが好き "、"麦本三歩は図書館が好き" といいった風に "麦本三歩は~~が好き" という風になっており、麦本三歩が好きな色々なものについて語られています。

読み進めていくにつれキュートな麦本散歩の日常に癒されまくりました。

以下、あらすじと感想を書いていきます。




『麦本三歩の好きなもの』のあらすじ


図書館勤務の20代新卒女子、麦本三歩のなにげない日々を三人称で描いた日常短編小説です。

麦本三歩の好きなものは朝寝坊とチーズ蒸しパンと本。性格は、ぼうっとしていて、おっちょこちょいで少し間抜けです。

彼女の周りは優しい人やおかしな先輩、怖い先輩など様々な人がいて三歩は日々翻弄されています。

この小説は特別な物語ではなく麦本三歩の当たり前の毎日を面白おかしく描いています。



感想(ネタバレあり)



キュートな麦本三歩


本作の主人公である麦本三歩はどこにでもいる普通の女性を描いていますが、なぜかとてもかわいらしく感じてしまい、魅力的です。

多くの読者が麦本三歩の可愛らしさに惹かれてしまったのではないのでしょうか。

私は、本作を読み進めていくにつれて麦本三歩のかわいらしさの虜にされてしまい、読み終わったころには麦本三歩のような友達がほしいと感じてしまいました。

麦本三歩には私たちが日ごろ当たり前だと思っている行動に対しても、好きになることができるポイントを見つけることができる力があります。

例えば作中で麦本三歩が紅茶を飲み、スーパーに売っているチーズ蒸しパンを食べているだけで幸せだと感じるシーンがあります。

こういった行動も初めて実行したときには私たちも幸せに感じるかもしれませんが、ルーティンにしてしまうと当たり前のことだと思い幸せには感じなくなってしまうでしょう。

しかし、麦本三歩ならばそんな当たり前の日常ですら毎日のように幸せであると感じることができます。

このように、あたりまえのことを幸せに感じることができる女性で、毎日を楽しそうに生きているからこそ、私たちは麦本三歩を可愛いと感じてしまうのでしょう。


また、麦本三歩には少し大食いであり、少しドジであるという二つの特徴があします。多くの人はこういった特徴を持つ人をかわいいと思ってしまう傾向があるのではないのでしょうか。

もちろん、ただ大食いだから好きになるのではなく、幸せそうに食事をしている描写が多いというのもあるとは思います。ドジなのもおかしな先輩のように好きではないと感じる人もいるかもしれませんが、多くの人は怖い先輩のようにかわいい奴だなと感じるでしょう。






『麦本三歩の好きなもの』の魅力


本書の魅力は先ほど述べた麦本三歩のかわいらしさもあると思いますが、それ以上に主人公が普通の女性であるため読んでいて共感ができるというところにあると思います。

たとえば "麦本三歩はモントレーが好き" では三歩は朝通勤しようとはしたもののなんとなく仕事に行きたくなくなったという理由で仕事をさぼってしまいます。

しかし、仕事をさぼったはいいものの罪悪感から翌日以降ずるをしてしまったということで三歩は一人苦しむことになります。

多くの人が三歩のこの状況を見て、自分もそんなことが過去にあったなどと共感できるのではないのでしょうか。しかも本書ではこの悩みを解決するために、ひとつの解決案を提示しているので三歩に見習って読者も次からはそうしようということができます

主人公がどこにでもいそうな普通の女性であるがゆえに、読者が共感をしやすいというのが本書の魅力だと私は思います。




この作品が伝えたいこと


本作は麦本三歩の日常を描いている作品です。この作品を通して住野よるさんは、読者に好きなものが増えれば人生が楽しくなるということを伝えたかったのではないのでしょうか。

忙しい現代社会では意味を見出すことができない行動を無駄であると感じがちです。

しかし、三歩のように意味がない行動の中に魅力を見出すことができれば、その無駄だと思っていた行動をすることが楽しくなり、人生が今より少し豊かになるのでしょう。

忙しいからこそ、少しの時間を楽しめる人間になることはとても大切だと思います。

私も三歩のように朝でかけるまでのわずかな時間を幸せに感じたり、色んなスーパーにそれぞれの特徴を見つけてその日の気分で買い物をするような自分の生活を楽しむことができる人間になりたい。



最後に


当たり前の日常を描いている作品でここまでおもしろい作品を久しぶりに読んだ気がします。

男性目線からは三歩がすごく好きになったのですが、女性の読者は本作を読んでどんな風に感じたのかが気になります。

*追記(2021/02/27)
『麦本三歩の好きなもの』の第二集が発売されました!!

また、第一作が文庫化されたみたいです!!








↑このページのトップヘ