クラスは、それ自身、何かしらの用途を想定して定義されるわけですが、比較的広い用途で利用されるクラスの場合など、メソッドが膨大な数になってしまう場合があります。
あまりに肥大したクラスは使いにくく、目的のメソッドを探すのも大変ですし、カスタマイズなどの管理面でも好ましくありません。このような場合には、クラスをカテゴリで分けて定義することができます。
また、カテゴリの仕組みは、クラスの拡張方法としても利用できます。オブジェクト指向の世界で最も一般的なクラスの拡張方法は、すでに紹介した継承の仕組みですが、継承による拡張ではあくまでも新たなクラスを1つ作成することになります。
それではちょっと大げさ過ぎる、もっと手軽にメソッドをいくつか追加したい、という場合には、カテゴリの仕組みが便利です。
クラスをカテゴライズする場合、ヘッダファイルと実装ファイルをそれぞれカテゴリごとに分けることもできますが、多くの場合、ヘッダファイルは1つにまとめ、実装ファイルをカテゴリごとに分割します。
例えば、Chef(料理人)クラスをJapanese、French、Chineseという3つのカテゴリに分けてそれぞれにメソッドを定義したい場合、1つのヘッダファイル、3つの実装ファイルに分けると以下のような構成になります。
クラスをあるカテゴリに分類して定義する場合、クラスの宣言部分および実装部分で、「@interface クラス名 (カテゴリ名)」「@implementation クラス名 (カテゴリ名)」のように記述します。カテゴリを指定したクラス定義では、メソッドは定義できますが、インスタンス変数は定義できません。
カテゴリに基づいてファイルを分割する場合、ファイル名は「クラス名+カテゴリ名.拡張子」のように命名する習慣があります。今回の例では実装部のみファイルを分けていますが、ヘッダを分ける場合も同様です。
それぞれの実装ファイルで、対応するヘッダファイルをimportすべきなのは従来と同じです。また、ヘッダファイルを分割する場合、各カテゴリのヘッダファイルでは、クラスの本体となる(カテゴリに属さない)ヘッダファイルをimportする必要があります。
上図の構成の、ファイル内容の例を以下に示します。
#import <Foundation/Foundation.h> |
Chef.h |
#import "Chef.h" |
Chef.m |
#import "Chef.h" |
Chef+Japanese.m |
#import "Chef.h" |
Chef+French.m |
#import "Chef.h" |
Chef+Chinese.m |
#import <Foundation/Foundation.h> |
main.m |
上記のような構成だと、クラスの宣言部分は1つのヘッダファイルにまとめられているので、カテゴリごとに整理された状態で、クラスの全体像を一望することができます。一方、実装部分はカテゴリごとに分かれていますので、後から編集する場合などにも長大なソースファイルを扱わずに済みます。
カテゴリ分けされたクラスを利用する場面(上記のmain.m)では、特にカテゴリを意識することなくメソッドを実行することができます。ただし、ヘッダファイルがカテゴリごとに分割されている場合には、実行したいメソッドが宣言されているヘッダファイルをimportしておく必要があります。
今回は、オブジェクト指向の一般的な話を含め、クラスをより体系的に扱う方法について解説しました。これらの仕組みを知っておくと、Foundationなどの基本クラス群についての理解も深まりますし、いわゆるデザインパターンと呼ばれるクラス設計の定石にも一歩近づくことができます。なによりも、効率的で堅牢(けんろう)なプログラムの作成に役立つはずです。
Copyright © ITmedia, Inc. All Rights Reserved.