クラスを拡張する3つの方法

ログを出力するクラスを作成します。
ログの出力先はファイルだったり、Memoコンポーネントだったりします。
出力処理を柔軟に拡張する方法について考えます。

ログ出力クラスの実装方法を3通り考えてみました。

  1. 継承
  2. 委譲
  3. メソッドポインタ

■継承…出力先ごとに派生クラスを作る

実装方法の一つに、出力先ごとに派生クラスを作る方法があります。
次のサンプルコードは基底クラスTLogを継承して、出力先ごとに派生クラスTLogFileとTLogMemoを作成しています。

/**
 * ログを出力する基底クラス
 */
class TLog
{
public:
  virtual ~TLog() {};
  virtual void Write(const UnicodeString Text) = 0;
};
/**
 * ログをファイルに出力するクラス
 */
class TLogFile : public TLog
{
public:
  TLogFile(const UnicodeString FileName)
    : FWriter(Ioutils::TFile::AppendText(FileName)) {}
  virtual void Write(const UnicodeString Text) { FWriter->WriteLine(Text); }
private:
  std::unique_ptr<TStreamWriter> FWriter;
};
/**
 * ログをTMemoに出力するクラス
 */
class TLogMemo : public TLog
{
public:
  TLogMemo(TMemo* Memo) : FMemo(Memo) {}
  virtual void Write(const UnicodeString Text) { FMemo->Lines->Add(Text); }
private:
  TMemo* FMemo;
};

使用例

TLog* log = new TLogMemo(Memo1);
//TLog* log = new TLogFile(L"C:\\test\\log.txt");
log->Write(L"test1");
log->Write(L"test2");

■委譲…出力処理を別のクラスにする

もう一つの方法として、出力処理だけを別のクラスにする方法があります。
次のサンプルプログラムでは、TLogクラスのコンストラクタの引数で渡されたオブジェクトにログの出力処理を委譲します。

/**
 * ログを出力するクラス
 */
template <class TLogWriter> class TLog
{
public:
  TLog(TLogWriter* Writer) : FWriter(Writer) {}
  void Write(const UnicodeString Text) { FWriter->Write(Text); }
private:
  std::unique_ptr<TLogWriter> FWriter; //出力処理を行うオブジェクト
};
/**
 * ファイルに出力するクラス
 */
class TLogFileWriter
{
public:
  TLogFileWriter(const UnicodeString FileName)
    : FWriter(Ioutils::TFile::AppendText(FileName)) {}
  ~TLogFileWriter() { FWriter->Close(); }
  void Write(const UnicodeString Text) { FWriter->WriteLine(Text); }
private:
  std::unique_ptr<TStreamWriter> FWriter;
};
/**
 * TMemoに出力するクラス
 */
class TLogMemoWriter
{
public:
  TLogMemoWriter(TMemo* Memo) : FMemo(Memo) {}
  void Write(const UnicodeString Text) { FMemo->Lines->Add(Text); }
private:
  TMemo* FMemo;
};

使用例

TLog<TLogMemoWriter>* log = new TLog<TLogMemoWriter>(new TLogMemoWriter(Memo1));
//TLog<TLogFileWriter>* log = new TLog<TLogFileWriter>(new TLogFileWriter(L"C:\\test\\log.txt"));
log->Write(L"test1");
log->Write(L"test2");

■メソッドポインタ…出力処理を差し替える

C++Builderではメソッドポインタでメンバ関数を差し替えるることができます。
次のサンプルコードは、ログの出力処理のメンバ関数をOnLogWriteプロパティで代入できるようにしています。

/**
 * ログを出力するクラス
 */
class TLog
{
//ログ出力処理関数の型
typedef void __fastcall (__closure *TLogWriteEvent)(const UnicodeString Text);
public:
  TLog() {}
  void Write(const UnicodeString Text) { FOnLogWrite(Text); };
  __property TLogWriteEvent OnLogWrite = { write=FOnLogWrite };
private:
  TLogWriteEvent FOnLogWrite; //ログ出力処理関数
};

ログ出力処理はフォームに記述することができます。

class TForm1 : public TForm
{
__published:    // IDE で管理されるコンポーネント
  TMemo *Memo1;
  void __fastcall Button1Click(TObject *Sender);
private:    // ユーザー宣言
  //ログ出力処理
  void __fastcall LowWrite(const UnicodeString Text);
public:     // ユーザー宣言
  __fastcall TForm1(TComponent* Owner);
};

//ログ出力処理
void __fastcall TForm1::LowWrite(const UnicodeString Text)
{
  Memo1->Lines->Add(Text);
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TLog log;
  log.OnLogWrite = this->LowWrite; //ログ出力関数を代入
  log.Write(L"test1");
  log.Write(L"test2");
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください