SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

C++/CX: Windows 8 ストアアプリことはじめ (2)

データ・バインディングのキホン

  • X ポスト
  • このエントリーをはてなブックマークに追加

 前回に引き続きC++/CXストアアプリ最初の一歩。データ・バインディングでUIとロジックとを分離します。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 前回の続き、データ・バインディングのおはなしです。前回こしらえたCounterAppではカウンタのUIを司るMainPage(View)がカウンタの実体(Model):Counterをメンバに持ち、ボタンのイベント・ハンドラ内でCounterを直接駆動してました。

 今回はこの実装をベースに、view-Model間の仲介役:ViewModelを両者間に差し込むことでViewとModelを分離します。こうすることでView/Modelそれぞれに対する拡張や変更が他方に及ぼす影響を小さく抑えることができます。画面デザイナとプログラマがそれぞれの作業を同時進行できるってわけ。

前準備:Counterの機能拡張

 その前に、いま一つ面白味に欠けるCounterに少しばかりの拡張:下限値/上限値設定機能を追加しておきますか。increment/decrementし放題な従来のカウンタはそのまま残しておいて、両者を好きに差し替えられるよう手を加えます。

list-1
// CounterLib.h
#pragma once

namespace CounterLib {

  // 抽象ベースクラス
  class Counter {
  public:
    Counter(int initial) : count_(initial) {}
    int get() const { return count_; }
    void set(int n) { count_ = n; }
    // ひとつ ふやす/へらす
    void increment() { do_increment(); }
    void decrement() { do_decrement(); }
    // ふやせる/へらせる か?
    bool can_increment() const { return do_can_increment(); }
    bool can_decrement() const { return do_can_decrement(); }
  protected:
    virtual void do_increment() =0;
    virtual void do_decrement() =0;
    virtual bool do_can_increment() const =0;
    virtual bool do_can_decrement() const =0;
  private:
    int count_;
  };

  // フツーのカウンタ
  class DefaultCounter : public Counter {
  public:
    DefaultCounter(int initial) : Counter(initial) {}
  protected:
    virtual void do_increment();
    virtual void do_decrement();
    virtual bool do_can_increment() const;
    virtual bool do_can_decrement() const;
  };

  // 下限値/上限値つきカウンタ
  class BoundedCounter : public Counter {
  public:
    BoundedCounter(int lo, int hi, int initial);
    BoundedCounter(int lo, int hi);
  protected:
    virtual void do_increment();
    virtual void do_decrement();
    virtual bool do_can_increment() const;
    virtual bool do_can_decrement() const;
  private:
    int lo_;
    int hi_;
  };
}
list-2
// CoutnerLib.cpp
#include "pch.h"
#include <cassert>
#include "CounterLib.h"

namespace CounterLib {

  // フツーのカウンタ
  void DefaultCounter::do_increment() { set(get()+1); }
  void DefaultCounter::do_decrement() { set(get()-1); }
  bool DefaultCounter::do_can_increment() const { return true; }
  bool DefaultCounter::do_can_decrement() const { return true; }

  // 下限値/上限値つきカウンタ
  BoundedCounter::BoundedCounter(int lo, int hi, int initial) : Counter(initial), lo_(lo), hi_(hi) {
    assert( lo <= initial );
    assert( initial <= hi );
  }
    
  BoundedCounter::BoundedCounter(int lo, int hi) : Counter((lo+hi)/2), lo_(lo), hi_(hi) {
    assert( lo <= hi );
  }

  // ふやせるならふやす
  void BoundedCounter::do_increment() {
    if ( can_increment() ) {
      set(get()+1);
    }
  }

  // へらせるならへらす
  void BoundedCounter::do_decrement() {
    if ( can_decrement() ) {
      set(get()-1);
    }
  }

  // 上限値に達していたらfalse
  bool BoundedCounter::do_can_increment() const {
    return get() < hi_;
  }

  // 下限値に達していたらfalse
  bool BoundedCounter::do_can_decrement() const {
    return lo_ < get();
  }

}

 DefaultCoutner/BoundedCounterそれぞれのテストを用意し、動作確認しておきます。

list-3
// DefaultCounterTest.cpp
#include "pch.h"
#include "CppUnitTest.h"
#include "CounterLib/CounterLib.h" // 追加

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace DefaultCounterTest {

  TEST_CLASS(DefaultCounterTest) {
  public:
    // 各テストの開始直前に行う
    TEST_METHOD_INITIALIZE(method_setup) {
      counter_ = new CounterLib::DefaultCounter(0);
      Assert::IsNotNull(counter_);
    }
    // 各テストの終了直後に行う
    TEST_METHOD_CLEANUP(method_teardown) {
      delete counter_;
    }

    // 初期状態でのカウント値は0
    TEST_METHOD(constructor) {
      Assert::AreEqual(0, counter_->get());
    }

    // incrementのたびにカウント値が+1される
    TEST_METHOD(increment) {
      for ( int i = 0; i < 10; ++i ) {
        Assert::AreEqual(i, counter_->get());
        counter_->increment();
      }
    }

    // decrementのたびにカウント値が-1される
    TEST_METHOD(decrement) {
      for ( int i = 0; i < 10; ++i ) {
        Assert::AreEqual(-i, counter_->get());
        counter_->decrement();
      }
    }
 
    private:
      CounterLib::Counter* counter_;
    };

}

会員登録無料すると、続きをお読みいただけます

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

次のページ
ViewとModelの分離

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/7130 2013/05/14 14:10

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング