2015年6月11日木曜日

ファイルの読み書きも間接参照で(作成理由編)

アプリで作成したデータを保存する場合、ファイルとして書き出すことが多いでしょう。作成データだけでなく、アプリの設定内容なども、ファイルとして保存することが多いはずです。

こうしたファイルに関する読み書きは、独自ライブラリとして用意し、それを使うことで、似たようなコードを何度も書かなくて済みます。ここまでなら、ライブラリ化が好きな人だと普通に行っているでしょう。

では、さらに1歩進めて設計するとしたら、どのような構造になるでしょうか。その辺の検討結果と、実際に作ったクラスを紹介ます。

 

まずアプリの一般的な構造を考えましょう。アプリの中心部分では、そのアプリに固有の情報を扱っていて、画面に表示したり、入力を求めたりします。入力されたデータや、外部から取得したデータを保存するとき、ファイルへ書き出すのが一般的です。

保存先としては、ファイル以外でも可能です。たとえば、ネット上のサーバーとか。つまりファイルとは、情報の保存先の1つでしかありません。

いくつかの中の1つである以上、切り替え可能なように作るのが良い作り方でしょう。保存先を単純に切り替えるだけでなく、同じ情報を複数に保存するとか、その片方への保存は1日に1回だけとか。切り替え可能な形で作っておくことで、保存する機能の拡張が格段にやりやすくなります。

つまり、アプリの内部構造として、中心部分の処理から、保存する処理を分離したいわけです。中心部分の処理では、どこに保存するのか、どんな名前で保存するのか、まったく知らない形となります。保存データを作った際には、保存する処理にデータを渡すだけで、あとは知らないという感じです。

 

以上のように考えた結果、ファイルの読み書きを間接参照で作ることにしました。ファイルの読み書きの基本的な部分は、すでにライブラリ化してあります。現状のアプリでは、それを直接呼び出しているのですが、今後は間接参照に変更しようということです。

間接参照をどのように作るのかが、一番重要です。大事な機能としては、保存先を切り替え可能に作る点があります。つまり、アプリの中心的な処理では、どこへ保存するのか知らなくても動くように作り、保存する処理が複数あって、それらが交換可能になるという形です。

そこで、間接参照を実現するためのリンククラスを用意することにしました。アプリ側では、このリンククラスのインスタンスを生成し、そのインスタンスへアクセスすることで、ファイルへの読み書きを実現します。具体的には、このリンククラスが、ファイルの読み書きのライブラリを呼び出して処理します。今まではアプリが、ファイル関連のライブラリを直接呼び出していましたが、改良版では、アプリがリンククラスを呼び出し、そのリンククラスがファイル関連のライブラリを呼び出します。また、どこへ保存するか、どんな名前で保存するかはリンククラスが持ち、アプリの中心処理では持たない形となります。

アプリがリンククラスのインスタンスを生成する際に、保存場所(ディレクトリ)とファイル名を指定します。そのため、ファイルとして保存するデータの数だけ、インスタンスを生成することになります。1つのファイル用に1つのインスタンスを生成するというルールです。

リンククラスで重要なのは、交換可能に作ることです。ネット経由での保存など、ファイル以外の保存先も考えられます。どの保存先でも共通のメソッドを持たせ、保存先が変更されても、ソースコードの変更を最小限に抑えます。

その実現で大事なのは、メソッド名と引数のデータ型です。これらが同じであれば、別なクラスに切り替えたとしても、修正箇所はたった2箇所だけになります。たとえば、変数名prefStorageで今回のリンククラスをインスタンス生成した場合、インスタンスへのアクセスは変数名prefStorageとメソッド名だけしか使いません。もしメソッド名が全部同じで、ネット上へ保存するリンククラスを別に用意したとき、次の2箇所だけ変更すれば良くなります。インスタンス生成するコードのリンククラス名を変更し、インスタンス生成で指定するする初期化の値(ディレクトリ位置やファイル名)を変えるだけです。それ以外のコードである、変数prefStorageへアクセスする箇所のコードは、変更しなくて済みます。このような形であれば、交換可能の良い実現方法でしょう。

以上のように考えると、ファイルの読み書きを強く意識したメソッド名(readやwrite)は適しません。もっと一般的なloadやsaveが、より適していると言えます。そこでリンククラスでは、メソッド名にloadとsaveを使うことにしました。

 

過去に作ったアプリを見ると、単純なloadとsaveだけでは不足です。デフォルト値を入れたファイルがあり、それを呼び出す機能も必要です。そこで、loadを2つ用意します。単純なloadと、デフォルト値のloadです。

以上を整理すると、次のようになります。とりあえず、ファイル編だけです。

リンククラスの主な仕様(ファイル編)
・保存先の情報を持つ:ディレクトリとファイル名
・初期化:保存先ディレクトリとファイル名を設定する
・保存メソッド:値を受け取ってファイルに保存する
・ロード・メソッド:保存されている値をロードする
・デフォルト値のロード・メソッド:デフォルト値をロードする

機能が少ないので、かなり単純なクラスになるでしょう。

 

さて、ここまでの話では、保存するデータの中身について触れていませんでした。保存データのデータ型が違うと、同じ処理を使えません。たとえば、ファイルから読み込む処理は、文字列、バイナリー、NSDictionary、NSArrayで違います。ファイルへ書き出す処理も同様です。つまり、扱うデータ型ごとに、別々なクラスを用意しないといけないわけです。

リンククラスの種類(ファイル編)
・文字列(文字コードはUTF-8)
・NSDictionary
・NSArray
・バイナリー

構造が簡単なクラスで、しかもファイルの読み書きライブラリが既に作成済みなので、作るのは簡単です。

それぞれのクラスでは、扱うデータの型が決められています。そのおかげで、コンパイラの型チェック機能が有効に働き、ちょっとした間違いなどをコンパイル時点で発見できるようになります。

 

リンククラスの作成理由を簡単に紹介するつもりでしたが、書いてみたら予想より長くなってしまいました。いつもの全体設計編というレベルではないので、作成理由編とし、ここで一旦区切ります。具体的なSwiftコードは、次の投稿にて。

0 件のコメント:

コメントを投稿