C++ 国際化

C, C++ で使われている国際化(initialization, i18n)について書いてみたいと思います。
細かいところは結構はしょって書いたのですが、いろいろ書いてしまって結構長いです。

国際化というのは主に言語(地域)ごとにメッセージを切り替えることを言います。 他にも通貨記号($)や時間の表し方も言語ごとに違いますし、少数点などはヨーロッパでは, . の使い方が逆だったりしてそれにあわせることなども含みますが、 今回はメッセージの切り替え中心です。

Un*x


C ではこの国際化は標準ライブラリにローケルという名前で古くからあります。
これはメッセージファイルに番号ごとのメッセージを書いておいて、 コード中では最初に言語を設定し、この番号を指定すると設定した言語のメッセージが取得できる という仕組みです。 普通はコード中に番号を直接書くことはしないでしょうから、 番号に対して define や列挙型をヘッダに記述しておいてそれを使うことになります。

この標準ライブラリはそのまま使おうとするとすごくめんどくさいです。 そのため、せっかくあるのになかなか使われず、国際化が進みませんでした。 そこでで出てきたのが GetText です。
これはベースは標準ライブラリを使用しますが、使いやすくなります。
プログラムを作る側は今まで英語メッセージを文字リテラルとして書いていたところを次のように _で囲むだけで済みます。
printf(_("Helow World.!!\n"));
このように書いたソースに対してツールを通すとメッセージファイルを作ってくれます。
訳す人はツールでメッセージが抜き出されたものができるので、それに対応する訳を書いて、 また、ツールを通すとその言語用のメッセージファイルが出来ます。

これで国際化が進んで、普通に日本語でアプリケーションが使えるようにとても良かったのですが、 個人的にはこの GetText はあまり好きではありません。
というのも、メッセージやアイコンなどはリソースというのですが、 このリソースはソースと分けて一括で管理したいためです。
翻訳用のメッセージはまとまっているのですが、デフォルトの言語(大抵は英語) はソースコードのあちこちに散らばることになりますし、修正する度にビルドのしなおしが必要となります。

今は国際化するのが当たり前になってきたので、もう GetText はいいんじゃないかと思うのですが、 Linux ではこれが主流です。
統合デスクトップ環境である gnome で使われえている GTK+ は GetText を使っていますし、 KDE の Qt は GetText ではなく独自の国際化を持っているのですが、これも GetText 方式です。

Linux ではない商用 Un*x の世界はというと、こちらの GUI は Motif というライブラリが古くから使われていて、これで CDE (gnome や KDE のもとになっているもの) も作られています。 Motif はさらに古い GUI ツールキットである Xt ライブラリの上に出来ているのですが、 こちらはきちんとリソースが分けられています。
Xt ではテキストファイルであるリソースファイルに以下のような行を書きます。
FooApp.FooDialog.OkButton.label : 了解 
キーになる方は親子関係で書くことができ、これを Widget の部品の名前とあわせておきます。 そうすると、アプリケーションは起動時にリソースファイルをロードして言語にあわせたラベルになります。
ただ、これは GUI 専用のところがあって、 エラーメッセージのようなコード中で決める文字列は C の国際化を使用する必要があります。

他に有名な国際化ライブラリで ICU というものがあります。
これはリソースの国際化だけではなく、文字コード変換などの機能も含んだ大掛かりなもので、 クロスプラットホームで動作します。 しかし、文字コード変換などは Boost からも使われるようになって、広く使われているのですが、 リソース管理という面ではそれほど使われていない気がします。
これもリソースを分離するタイプでよく考えられていると思うのですが、 やはり、 GUI ツールキットとセットではないと広まりにくいのかも知れません。

Windows


Windows の場合、 .NET 以前は基本的に C の標準ライブラリのようなもので、 番号(ID)に対して文字列を指定し、 ID を指定して文字列を取得します。
ただ、 Visual Studio のような IDE で作るのが普通なので、 メッセージファイルの作成と番号の define 定義が同時にできるような感じになっていて、 そんなに使いづらくもないかなと思います。
.NET では番号を define したものではなく、 'Foo.Bar.Ok' のような文字列で取得できるようになっています。

Windows ではリソースは exe や dll などのバイナリファイルに埋め込んでしまいます。 なので、翻訳がない場合に問題が出てきます。
Un*x 系では言語の指定は環境変数 LANG で行いますが、 Windows では WIN32API などの OS が提供するライブラリでユーザーが設定している言語を取得してきます。
商用アプリなど売るところが決まっている場合は問題ないのですが、 フリーウェアなどの場合はリソース用の dll などで追加して、 言語の設定を自動で行うのではなく、アプリの設定でユーザーがどの言語を選択するかを指定するといった工夫が必要になります。

Un*x 系はというと翻訳ファイルやリソースは分かれているのが普通なので、 翻訳ファイルの置き場所に翻訳ファイルおいてなければデフォルト言語(英語)で表示して、 翻訳を追加したければ、そこにファイルを置くという方式が多いと思います。

ちなみに Qt はクロスプラットホームなので、アイコンなどのリソースを Un*x でも、がんばって取り込む仕組みを持っています。 ただ、翻訳ファイルは別ファイルになっていて、 Un*x のような追加方式にすることもできなくはありません。
できなくはないというのは、見つからなかったら英語にする仕組みはないので、 その辺はアプリ側で実装する必要があったりします。


といった感じが C++ での基本的な国際化の方法じゃないかと思います。
どれも一長一短といった感じで、これだっと言うものはないです。 強いて言えば、 .NET が良いと思うのですが、クロスプラットホームではないです。
(Linux でも動くんじゃないかって話はありますが)

それでクロスプラットホームの大規模のアプリの中には自前で国際化の仕組みをもったものもあります。
例えば、 firefox, thunderbird の Mozilla では テキストファイルである プロパティファイルや DTD を使った Java っぽい国際化ができるようになっています。

スポンサーサイト
 

国際化 - Unicode と文字列クラス

国際化の話、第 2 弾ということで Unicode とその限界、それと C++, Ruby での文字列の持ち方について書いてみたいと思います。

Unicode


国際化といえば Unicode なのですが、 登場までの流れを少し説明したいと思います。
C では文字列は基本は 1 バイトの char 型の配列です。
ただ、 1 バイトだと最大で 255 (0 は文字の末端として使います) 種類しか区別ができません。 英語だとそれで十分なのですが、日本語だとアルファベットもあわせるとひらがなぐらいしか入りません。 昔は文字の大きさもアルファベットに合わせる必要があったため、 ひらがなは表示が難しいので、カタカナにして、日本語はカタカナだけ使えるという時代がありました。 この名残が半角カタカナです。
英語などの文字の少ない言語しか対応できないようではだめだってことで、C では日本語などを入れるように 2 バイトの wchar_t 型を作って 日本語などは wchar_t 型の配列(ワイド文字列)に入れたらということになりました。 しかし、英語用に char 型できていたプログラムを wchar_t に変えるのは変更が大きすぎます。

そこで char 型の配列にいれるために 1 文字を複数のバイトで表すマルチバイト文字列が使われることになります。 これが Windows(MS-DOS)ではシフト JIS で、 Un*x では EUC です。あと JIS(ISO-2022-JP)もあります。
シフト JIS 、 EUC はそれぞれの種類の OS で使われているものですが、なぜ JIS があるかというと通信用で 7 bit の文字コードが必要だったためです。 英語は 255 種類も必要なく、 1 bit 減らした 125 種類で十分なので、 ASCII コードは 7 bit しか使いません。 昔は 1 ビットでも通信量を減らしたいということがあり、 8 ビット目を切り落として、詰めてデータを送る通信方式がありました。 このため 7 bit の文字コードが必要となっていました。 この JIS コードは 7 bit に切り詰めている分、かなり使いづらいコードなので、プログラム中では、シフト JIS や EUC を使って、通信する前に JIS コードに変えるというように使われていました。しかし、最近ではそんな方式は使わないようになっているので、 JIS コードはほとんど見かけなくなりました。

修正を減らすためのマルチバイト文字列だったのですが、これはこれで扱いが難しいです。
よくある問題が漢字を含む Windows のパスでパス区切りの \ を探そうとすると 2 バイト構成されている漢字の中の 1 バイトに \ がひっかかって ちゃんと検索できないといったものです。 EUC はシフト JIS より後発のため、多少改善されてますが、 同じような問題はあります。

シェアを広げるためには、国際化は必須です。 しかし、やっぱり 1 文字は 1 つのデータとして扱わないとプログラミングのコストがかかります。
そこで Microsoft をはじめ、大手企業が乗り出してきて、登場したのが Unicode です。 これで 1 文字を 2 バイトに格納する仕様が決まり、最初の wchar_t に脚光がもどってきました。

UTF-8


文字を 2 バイトで扱うようにしたことによって、新たな問題も生じます。 2 バイトだとファイルや通信などで OS をまたぐ際にはエンディアンを考慮する必要が出てきます。
Unicode をそのままファイル落とすとビックエンディアンかリトルエンディアンか分からないので、 先頭にエンディアンを区別のための BOM を付けたものが UTF-16 で UTF-16BE と UTF-16LE があります。
ただ、これをテキストファイルの標準にしようとすると今までのプログラムをほとんど変える必要があります。 英語だけの文字の場合には ASCII コードと同じものとして扱えるようにしたものが UTF-8 です。英語を優遇した結果どこかにしわ寄せがくるもので、日本語などは今まで 2 バイトだったものが文字によって 3, 4 バイト使うことになります。

いまだに 7 bit 通信を考慮した UTF-7 や日本語のデータ量をそんなに増やさずにすむ UTF-9 といった規格もあるようですが、使われていないようです。

日本語を保存したときのデータ量が増えるとはいえ、 Unicode を使うと英語などの言語は 文字のメモリ使用量が 2 倍になるんだし、それに比べれば UTF-8 が使われていくのは、仕方ないかなと思います。
しかし、本来 1 バイトのため、エンディアンを考慮する必要のない UTF-8 ですが、 UTF-8 を使っているという識別のために BOM 付きの UTF-8 というものがあります。
しかも今は BOM 付きだと動かないものと BOM なしだとちゃんと認識してくれないものが混在していて、なんとかしてよという気がします。


Un*x


Unicode と UTF-8 の説明が終わったところで、実際にプログラムではどういった感じで文字列データを持っているのか という話に移りたいと思います。

QtQString という文字列クラスを使っていて、これには 2 バイトの Unicode が格納されています。 ファイルなどの外部から文字を取り込むときに Unicode にして、プログラム中では Unicode で処理するという一番、一般的なタイプだと思います。
Java や Perl などもこのタイプです。

GLib と glib を使っている GTK+ は、プログラム中は Unicode ではなく、 UTF-8 を使います。
文字列を取り込むときに UTF-8 に変換して、各関数は UTF-8 のマルチバイト処理だけ対応している感じです。データの型は一応 GString という文字列を格納する型はあるのですが、 全部これに入れてから使うという感じでもなく、 C の char 型配列が主に使われています。

Motif はというと、私が知らないだけかも知れませんが、 Unicode で統一しようという動きはなく、 いまだに EUC が使われている気がします。

Windows


Windows は .NET 以前は複雑です。
コンパイル時に _UNICODE の定義があるかないかで char と wchar_t が切り替わる TCHAR 型というものを使っています。
文字と文字列リテラルはワイド文字列の場合、前に L を付けるのですが、これも _UNICODE で切り替わるようにリテラルは _T のマクロで囲む必要があります。
char *str = "Hello";
wchar_t *wstr = L"Hello";
TCHAR *tstr = _T("Hello");
また、 MFC には CString という文字列クラスがあるのですが、 これも中に格納するデータは定義で char と wchar_t が切り替わっています。
さらに COM を使うということになると BSTR というデータ構造を使う必要があります。

.NET では文字列は System::String クラスで、これは 2 バイトの Unicode が格納されます。
ただ、これも値を変更できない変わったクラスではあります。

ちなみに Qt でも文字列リテラルを囲む _T は使用します。
MFC からの移植を簡単にするため、同じ名前にしたのでしょうが、 MFC の _T とは別ものです。 これは GetText の N_ や _ の役割と文字列リテラル(char *)を QString に変える役割をもっています。

C++ 標準ライブラリ


C++ の標準ライブラリでは std::string とワイド文字列用の std::wstring があります。 これはテンプレートでクラスで定義されたものに char と wchar_t をテンプレートの引数に渡した型を typedef したものです。 string と iostream はテンプレートを使って実装されていますが、 テンプレートとして使っているわけでは無いので、標準ライブラリではありますが、 STL には含まれないそうです。

string は C++ での char 配列の代わりとしてよく使われますが、 wstring は使われる場面は限られます。
GLib, Qt, MFC, .NET が使えない環境で日本語の文字列処理が必要な場合です。
それってどこだよという感じですが、私はクロスプラットホームで動作する コマンドラインプログラムを作ったときに使ったことがあります。 (Qt はラインセンスの関係で使いませんでした)

Unicode の限界


広く使われるようになった Unicode ですが、実は問題を含んでいます。
それは世界で使われてる文字を入れるのに 2 バイトでは足りないということです。
32 bit の大部分を使っているのは、中国、台湾、日本の漢字圏です。 そこで、 3 つの国で似ている漢字を一緒にしちゃえってことで、 無理やり 2 バイトに押し込めました。
(アルファベットに関しては、フォントで分けるべきものじゃないかというのまで、分けられているのですが...)
それでも、日本語だけ使うのであれば、特に問題はありません。
問題は日本語と中国語などを同時に使う場合です。 Unicode を使っていると 一部の文字がどちらの言語か判別できず、正確に表示されないということになってしまいます。 つまり、 Unicode では国際化はできるけど、多言語化はできません

4 バイトの Unicode を使えばいいのですが、さすがに文字データが 4 倍のメモリを使用するのは、なかなか採用されないでしょう。
多言語化はされないのか、多言語化したとき漢字が少し変になるぐらいかまわないと思われているのか 分かりませんが、世の中はどんどん 2 バイトの Unicode で統一されていっています。

Ruby の多言語化


そんな中、日本発のプログラミング言語はやっぱり違います。
Ruby はちゃんと多言語化に対応してしまいました。
標準に採用されている XML パーサーや Rails が UTF-8 で統一されているので、 GLib のような UTF-8 で統一する方針なのかなと思いきや、 Version 1.9 で多言語化(Multilingualization, M17N)が導入されました。

どうやっているかというと、 文字列クラス String のインスタンス 1 つ 1 つで自分が今どの文字コードなのか という文字コード情報を持っています。検索などの文字列処理関数は文字列のその情報をみて、 それにあった方式で処理することになります。
この方式では 1 文字で 1 単位というわけではないので、マルチバイト文字と同じ問題が発生するため C のようにポインタでまわして自分で中を見ていくということはできず、文字列には必ず文字列処理用の関数を通して扱う必要があります。
ただ、 Ruby ではもともと EUC やシフト JIS に対応していて、 C と違ってすでにずっとそういう方針だったので、特に違和感はありません。

また、文字コード情報は 8 バイト程度でしょうから、それが付いているだけで、 ASCII 文字では 1 バイト、日本語も 2 バイトと文字データのメモリ使用量が減ります。

Ruby の多言語化は素晴らしいのは素晴らしいのですが、 スクリプトの結果を表示するターミナルや GUI が Unicode で統一されていっているので、 結局、ちゃんと表示できるようにはならないでしょう。
Ruby の GUI ライブラリはいろいろあるのですが、基本的に C++ のライブラリを Ruby で使えるようにしたものなので、 XLib や WIN32API からごりごり作った Ruby 用のクロスプラットホームで使える GUI ツールキットができたらいいなと思います。
これは Ruby アソシエーションが開発プロジェクトを公募しているとき、やろうかとちょっと頭をよぎったのですが、 個人で 1 年でできるようなレベルのものじゃないなということでやめました。

 

雑把の UI アーキテクチャー史(MVCからMVVMへ)

今回は UI アーキテクチャーの歴史についてです。

もともとスライドだったのですが、 説明を追加して、記事にしてみました。
最初は MVVM の簡単な説明のつもりでしたが、 MVC とその問題点を付けて、 最近の UI 開発の傾向を書いて、とやっているうちに変に広がった内容になってます。



スライド版はこちらです。





ここからブログ版です。

目次

  1. MVC 以前
  2. MVC - 拡張 MVC 時代
  3. MVVM(.NET)
  4. .NET 以外の傾向

MVC 以前

最初に MVC 以前の状態とともに UI アーキテクチャーにおける前提ついてお話します。

UI アーキテクチャーの大前提

MVC 以降いろいろな UI アーキテクチャーが登場しますが、 共通している目的は アプリケーションのコア部分と UI 部分を分離する ということです。

これはかっこよく言うと、次のようになります。
ビジネスロジックとプレゼンテーションロジックを分割する

MVC 以前ではそれらを 1 つのオブジェクトにまとめる傾向があったらしいです。
MVC 自体は賛否両論あるかも知れませんが、 そういった考えが広まり、 UI アーキテクチャーが注目されるきっかけとなったことは 大きな意味があると思います。



もう一つ最初に伝えておくべきことは 完璧な UI アーキテクチャーはない ということです。

銀の弾丸などない という格言があります。
ソフトウェア開発では、魔法のように問題を解決するような技術は存在しないことを示唆する言葉です。 これは UI アーキテクチャーでも同様です。

そのため、最後に出てきた UI アーキテクチャーでも決定版とはなりません。
問題がでてきて、新しいものが生まれるという繰り返しが今後も続いていくでしょう。

MVC と 拡張 MVC

MVC (GoF 本)

MVC が広くつかわれるようになったのは、 『 GoF 本』 で紹介されたことが大きかったでしょう。
そこで、『 GoF 本』 での MVC から始めることにします。
prog_mvc_gof.png
モジュール 説明
Model アプリケーションオブジェクト、データ管理
View 画面の表現
Controller ユーザー入力に対するインターフェース



もう少しわかりやすいように Wikipedia にあったシナリオをコラボレーション図風にしました。
prog_mvc_wikipedia.png



今までの説明で MVC は理解できたでしょうか ?

Model 、 View の方はわりとわかりやすいと思います。
しかし、 Controller はわかりづらいです。 ユーザー入力に対するインターフェースといわれても、 "View に入るんじゃないの ?" と思う人も多いでしょう。

また、ちゃんと理解できたとしても、"もっといい方法があるんじゃないか" と指摘したい点も多々あるんじゃないでしょうか。
例えば、 私は Model から View へ矢印がでているのは、結合が密になりよくないと思います。


誤解されたり、改良されたりで、 MVC は人によって解釈が様々になってしまっているのが現状です。
MVC が何を指しているのか、はっきり言って正解はわかりません。

今度は、この変化していった Web、 PC での MVC について見ていきます。

MVC (Web)

Web サービスで広く使われている MVC フレームワークとして Ruby on Rails があります。 これは次のようなアーキテクチャーです。
prog_mvc_rails.png
モジュール 説明
Model DB へのアクセス
View html ページと html ページの作成
Controller 入力の受け取り。他のモジュールの操作
Web の場合は View と Controller の違いははっきりしてます。
View は html ページとその作成を担当します。 CGI は アドレスとパラメーター(アドレスの ? の後など)を受け取り、処理を行います。 その受け取り部分が Controller です。



Model と View ではなく、なぜ MVC としたのでしょうか ?

『 GoF 本』 では Controller を分ける利点をいくつか挙げられています。
  • キーボードの応答を変えたり、メニューからの呼び出しに変更するとき、表示方法を変更しなくていい。
  • 入力イベントを無視するといったことをコントローラーのインスタンスの入れ替えで可能。
その他にも "View を入れ替えれば、 PC アプリ、 Web アプリでも使えるように" という理由もあります。
ちょっと無理そうな話ですが、例えば、 PC アプリが次のような構成であれば、 入れ替えて使うということができるかも知れません。
prog_mvc_pc_mvc.png
ただし、アプリが複雑化してくると、すぐ厳しくなってくるはずです。
やはり、これは欲張りすぎというものでしょう。

拡張 MVC (PC アプリ)

次に PC 上で動作するデスクトップアプリケーションの場合です。
この場合は、 Widget や Control といった GUI ツールキットが提供する部品を組み合わせて作成します。

高機能な部品になってくると、どうしても表示と入力処理を兼ね合わせるものになってしまいます。 このため、 View と Controller の分離は不可能になってきます。

『 GoF 本』 で指摘されている機能はほとんど GUI 部品の方で機能を持っていますし、 普通は PC 向けだけに作るので、あまり Controller を分ける必要もありません。


そこで、でてきたのが V と C をまとめて View とする拡張 MVC です。 (拡張といいつつ、減っていますが...)
これは、コアと UI 分離という基本原則だけ残った形です。
prog_mvc_ex.png
拡張 MVC は GUI ツールキットによっては次のような呼ばれ方もします。
  • MFC : Document - View
  • Qt : Model - View

問題点

次のような状態でしばし落ち着きます。
対象 UI アーキテクチャー
PC 拡張 MVC (MV)
Web MVC

ただし、 拡張 MVC に問題がないわけではありません。
それは View の肥大化 です。

もともと大して分けてないので、 プログラムの 8, 9 割が View というのも珍しくありません。
ちゃんと意識して作らないと、全部 View で MVC 以前に戻ることもありえます。
そこで、"なんとか分けなきゃ" となります。


一方、 Web は Web で Google の Web アプリのような高機能なものが求められ、 JavaScript が大規模化し、 こちらも View の肥大化が起こります。

UI アーキテクチャーの乱立

問題点の解決ためにいろいろな UI アーキテクチャーが考案されます。
  • MVP - Model, View, Presenter
  • PM - プレゼンテーションモデル
  • アプリケーションモデル
これらのアーキテクチャーについては次のサイトで詳しく説明されています。 ただし、ここで MVC の拡大解釈が話を複雑にします。
例えば、 MVP の Presenter は簡単にいうと M と V の "つなぎ" の役割ですが、 Controller の名前でそのように使われることもあります。

また、 こういった UI アーキテクチャーは GUI ツールキットなどで、 フレームワークとして提供されないとなかなか定着しづらいものです。

要望

新たな要望も出てきます。
これはデザインの重要性が高まりからきています。

Web サイトは大手企業などでは Web デザイナーが作成しています。 それと同じように画面デザインもデザイナーに任せたいという要望です。

しかし、そのためには 画面レイアウトとコードを分離する必要が出てきます。
ただ、これは GUI ビルダーでも、昔から試行錯誤されているところなので、古くからの要求ともいえます。

画面レイアウト、コード分離の難点

GUI アプリケーションでは必然的にイベント駆動プログラミングとなります。
これが分離のネックです。

イベント駆動では呼び方はいろいろありますが、基本的に次のような仕組みです。
  • シグナル(イベント) → コールバック
prog_mvc_event.png
  • ループで画面を表示
  • イベント発生(ボタンクリックなど)
  • コールバック関数が呼ばれ、処理を実行
  • ループに戻る
このボタンなどの部品とコード上で定義されたコールバック関数を結び付ける必要があります。

MVVM(.NET)

問題点の解決のため、 .NET では MVVM が使わるようになってきました。

.NET の登場

  1. Win32API と MFC
  2. Java の台頭
  3. C#、.NET で対抗
1.
Windows での GUI のベースは C 用の Win32API です。
.NET 登場以前は VC++ では API をラップした MFC が使われていました。 C のラッパーなので、オブジェクト指向でできていないとか、 C++ でしか使えないといった批判がありました。

2.
そんな中 Java が出て来ました。
Java はガベージコレクションなどの機能で C++ よりも開発しやすく、しかもクロスプラットフォームです。
また、 Linux も gnome や KDE などで使いやすくなってきていました。
アプリケーション開発をみんな Java に移行され、 そのアプリが OS を選ばずに動作するとなれば、 開発ツールだけでなく、 Windows からユーザーをごっそり持っていかれる危険性が出てきます。

3.
そこで MS が対抗して出したのが C# と .NET です。
ただし、そこで最初に用意された Form は従来の部品を .NET 用にラップしたもので、 ピュア .NET ではありませんでした。
『 6 つの UI アーキテクチャ・パターン』での紹介では フォームとコントロール ですが、これはまだ拡張 MVC のままといってもいいでしょう。

WPF

その後、.NET 用に作りなおされた GUI ツールキットとして登場したのが、 WPF です。


しかし、なかなか広まっていないのが現状です。
おそらく、原因は次のようなところでしょう。
  • Form の方が部品が多機能で豊富
    • 従来の部品を使っているからこそ、今までの蓄積分があり、 WPF の部品が貧相に見えてしまいます。
  • 使い方がわかりづらい
    • WPF では VS で部品を配置した後、ハタと次どうすればいいかわからなくなってしまいます。 Form の方が使い方は想像しやすいです。
      また、使っている人が少ない → いいドキュメントも少ない ということもあります。
  • 長い間 MS 製品ですら使われなかった
    • 「さぁ、使ってください」と出された WPF ですが、 使う場合には「本当に実用に耐えうるの ? 」 というのは気になるところです。
      そんな中、 MS 自身が自分のところの開発に使っていないとなると「大丈夫かこれ。」と思うのは当然でしょう。

MVVM の登場

WPF はなかなか使われません。 しかし、だからといって Form のままでは問題点と要望が解決できません。
  • View の肥大化
  • 画面レイアウトとコードの分離
ここで問題解決のための MVVM の登場となります。
流れとしては MVP → PM → MVVM といった感じです。 と、その前に採用されている技術を紹介しましょう。
  • データバインディング
  • コマンドパターン

データバインディング

今更ですが、データを扱う部分は Data や Core ではなく、 何故 Model というのでしょうか ?

ここでの Model の意味はモデル化、モデリングといった時と同じで抽象化の意味です。
データは XML ファイルや DB などですが、これをプログラム内では扱いやすい構造体(オブジェクト)などに変換して使います。 データそのものではなく、構造体などに抽象化しているところなので、 Model です。
prog_mvc_databind.png

デスクトップアプリでは、 Model 内でデータを構造体(オブジェクト)として直接管理することもありますが、 多くはファイル、 DB から構造体(オブジェクト)に変換する必要があります。
この技術をデータバインディング といいます。
ただ、 プログラミング言語にメタプログラミング(リフレクション)の機能が必要だったり、 C++ のようにそれがない言語では特殊な前処理が必要だったりとそうそう簡単にできるものでもありません。

設定画面でよくあるパターン

『 GoF 本』にでてくるようなパターンではありませんが、 設定画面などでよく使われる手法があります。

それは画面の内容と構造体(オブジェクト)との相互に変換する機能を持たせることです。
デフォルト値があったり、部品の値がそのまま確定ではないモーダルなダイアログだったりする場合に向いています。
prog_mvc_vdatabind.png
通常、この変換は自分で実装しないといけないのですが、 WPF ではこの実装を助ける機能があり、双方向データバインディングと呼ばれています。


これ、 Model で使われるものと似ていないでしょうか ?
画面(View)を構造体(オブジェクト)に変換することで、抽象化しています。 ViewModel の由来は View 用の Model というところからきています。

双方向データバインディングにより、 ViewModel のオブジェクトの値を変更すると画面が変更され、逆に画面を変更すると ViewModel の値が変わります。 画面を抽象化した ViewModel としておくことで、プレゼンテーションロジックのテストがやりやすくなります

コマンドパターン

こちらは『 GoF 本』にもでてくるパターンです。

要求をオブジェクトでカプセル化するパターンで、 いろいろなところからの呼び出しに対応しやすくなります。
prog_mvc_command.png

MVVM

MVVM は次のような構成です。
prog_mvc_mvvm.png

画面レイアウトとコードの分離

View
XAML : XML でレイアウト定義
ViewModel
  • データ: 双方向バインディングで同期 (大部分をこれで行う)
  • コマンド : 必要最小限のイベント駆動
View で画面の作成を行い、このレイアウト定義を XML に記述します。
これにより、 画面デザインは Expression Blend などのデザインツールで行えるようになります。

パラメーター項目の設定などはデータバンディングを使い、 [OK] ボタンを押すといった必要最小限だけイベント駆動にします。
これにより、なるべくコードと分離しています。

View の分割

拡張 MVC (MV) における View の部分を ViewViewModel に分割することで肥大化を軽減しています。

ただ、 ViewModel がコマンドの管理だけならば、 Controller と区別しづらく、MVC に取り込まれていたかもしれません。
データバインドが MVVM の特徴です。

逆にデータバインドの機構がないと実装が大変なため、 MVVM は WPF 用の UI アーキテクチャー と言えます。

MVVM の実装

確かに MVVM は WPF 用の UI アーキテクチャーです。
しかし、注意していただきたいのは、 WPF は MVVM フレームワークではないということです。

これは次のようなことを意味します。
  • WPF で作れば MVVM になるわけではない
    • MVVM のアーキテクチャーを崩さないよう意識して実装する必要がある
  • MVVM を実装するには毎回同じようなコードを書く必要がある
毎回同じようなコードを書くのは面倒なことです。 そこで MVVM 用のライブラリー(フレームワーク)がいくつか存在します。
(『 MVVM 入門 その4「ライブラリを使おう」 言語: C# Visual Studio 2010 用』)

.NET 以外の傾向

.NET 以外にも、最近の傾向について触れておきます。

Web アプリケーション

問題のところで Web では JavaScript の部分が大規模化していると記述しました。
この解決策としては、 JavaScript の部分もフレームワークを使うというものがあります。
prog_mvc_js_mvc.png
よく使われるフレームワークは Backbone.jsAngularJS といったもので、 MVC が主流のようです。


2 段構えになってややこしいですが、 JavaScript はセキュリティ上、サーバー側のアクセスには制約があり、仕方ないところでしょう。
ただ、 最近は Node.js などのサーバーサイド JavaScript もあり、 コードを共有化して減らすといった工夫もできます。

また、 JavaScript には "スクリプトのわりに書きづらい"、 "大規模開発に向いていない" といった欠点があります。このため、 変換系の新言語や Dart に移行するという流れもあります。 MVVM にはデータバインディングが必要と書きましたが、 実は Dart の UI パッケージにもデータバインディングの機能があります。
ただし、こちらは MDV(model-driven view) というアーキテクチャーを採用しているようです。

モバイル

スマホ、タブレットの出現により、 今までの PC 、 Web に加え、 モバイルという分野ができてきました。

このモバイル用アプリは標準では次の言語で開発します。
OS 言語
iOS Objective-C
Android Java

しかし、 iOS 用のアプリを作ったら、 次は Android 版もというのが自然な流れです。
当然、ソースコードはなるべく共通化したいでしょう。

そのため、いろいろな言語での開発環境が出てきています。 注目されているのは、これだと思います。
HTML5 + JavaScript
JQuery MobileTitanium といったフレームワークがあります。

.NET 以外の PC アプリ

.NET 以外の PC アプリでも Mozilla の XUL、 Qt の QML のように 画面レイアウト定義に XML が使われる傾向があります。
.NET と違うのは、これらは HTML のように JavaScript を使います。 JavaScript をにかわ(glue)言語として使う構成です。
prog_mvc_js_pc.png
対象 作成
画面レイアウト XML
GUI 部品 GUI ツールキットが提供(C++)
アプリケーション全体 JavaScript
コア、スピードネック部分 C++
また、 GNOME でも GUI アプリは JavaScript を使うようになって来ています。

今後、どうなる ?

Web アプリでは同一のソースを PC ブラウザー、スマホ、タブレットのそれぞれの画面にあわせて表示する レスポンシブ Web デザインという技術が注目されています。
これはモバイルアプリでも必要な技術です。
HTML5 + JavaScriptで Web 、 モバイルは統一化される傾向があり、 実際 Titanium では、共通のソースで作成できるようです。


シェアはかなり小さいですが、 MS も Windows Phone というスマホ用の OS を出しています。
こちらの開発環境は PC 版から機能を削った SilverLight です。 SilverLight でも WPF と同様に MVVM が使えます。

Windows 8 のタッチパネル対応などもあり、 .NET では PC 、 モバイルの統一化の傾向が見受けられます。

モバイルの Titanium から派生した TideSDK では HTML5 + JavaScript といった Web の技術で PC アプリを開発できます。
こうやってみてくると Web 、 モバイル、 PC の開発が近づいてきているようです。
MVC の頃は PC と Web の共通化は無理と思ったものですが、 3 つの共通化が実現できる日がくるかも知れません。


 
このページをシェア
アクセスカウンター
アクセスランキング
[ジャンルランキング]
コンピュータ
36位
アクセスランキングを見る>>

[サブジャンルランキング]
プログラミング
3位
アクセスランキングを見る>>
カレンダー(アーカイブ)
プルダウン 降順 昇順 年別

02月 | 2017年03月 | 03月
- - - 1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31 -


はてな新着記事
はてな人気記事
ブロとも申請フォーム
プロフィール

yohshiy

Author:yohshiy
職業プログラマー。
仕事は主に C++ ですが、軽い言語マニアなので、色々使っています。

はてブ:yohshiy のブックマーク
Twitter:@yohshiy

サイト紹介
プログラミング好きのブログです。プログラミング関連の話題や公開ソフトの開発記などを雑多に書いてます。ただ、たまに英語やネット系の話になることも。