次に、記事「オブジェクトに必要な4つの特性とは?」にある「カプセル化」について考えてみましょう。この記事ではカプセル化の例の1つとして、「公開されている「インターフェース」以外にオブジェクトの状態に直接アクセスできない(情報隠ぺい)」とあります。実は、これもすでに実現しています。
例えば、ViewControllerクラスとPersonクラスについて考えてみましょう。ViewControllerからはPersonクラスの属性である_nameや_ageを勝手に変更することはできません。
_nameを変更するには「- (NSString *)nameメソッド」や「- (void)setName:(NSString *)name」メソッドを介してのみ行えるようになっています。
また、Person.hとPerson.mを以下のように変更してみましょう。
#import <Foundation/Foundation.h> @interface Person : NSObject { // 性 NSString *_lastName; // 名 NSString *_firstName; } // 性を設定する - (void)setLastName:(NSString *)lastName; // 名を設定する - (void)setFirstName:(NSString *)firstName; // 名前を取得する - (NSString *)name; @end
#import "Person.h" @implementation Person // 性を設定する - (void)setLastName:(NSString *)lastName { _lastName = lastName; } // 名を設定する - (void)setFirstName:(NSString *)firstName { _firstName = firstName; } // 名前を取得する - (NSString *)name { return [NSString stringWithFormat:@"%@%@", _lastName, _firstName]; } @end
併せてViewController.mを以下のように変更します。
#import "ViewController.h" // Personクラスをインポートする #import "Person.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Personクラスのインスタンスを生成する Person *yuki = [[Person alloc] init]; // 性を設定する [yuki setLastName:@"平井"]; // 名を設定する [yuki setFirstName:@"祐樹"]; // 名前をコンソールに表示する NSLog(@"こんにちは、私の名前は%@です。", [yuki name]); } @end
これを実行すると、コンソールに以下のように実行されます。
このとき、性と名の間にスペースを入れたくなったとします。その場合は、Personクラスの「- (NSString *)name」メソッドのみ変更すればよく、ViewControllerに一切手を加える必要はありません。
#import "Person.h" @implementation Person // 性を設定する - (void)setLastName:(NSString *)lastName { _lastName = lastName; } // 名を設定する - (void)setFirstName:(NSString *)firstName { _firstName = firstName; } // 名前を取得する - (NSString *)name { return [NSString stringWithFormat:@"%@ %@", _lastName, _firstName]; } @end
実行結果は以下のようになります。
このように、Objective-Cでは、カプセル化を実現できることが分かります。
人間にもたくさんの種類があります。例えば、日本人、アメリカ人などのように国籍別、またはSE、警察官などのように職業別に分類できます。オブジェクト指向では、これらの「関係」を表せます。
例えば、学生というクラスを考えてみましょう。学生は学校名、学科、学年などさまざまなメンバー変数を持つことが考えられます。これらのメンバー変数はPersonクラスには定義されておりません。しかし、学生も人間です。
この関係を表すために、オブジェクト指向では「継承」という概念を用います。継承を用いることで、あるクラスが他のクラスの特性を引き継ぐことができます。ですから、学生クラスは人間クラスを継承することで、人間クラスの特性を引き継ぐことができます。
このとき、人間クラスは「スーパークラス」「抽象クラス」「親クラス」などのように表現します。学生クラスは「サブクラス」「派生クラス」「子クラス」などのように表現します。
また、このことを「サブクラス化」ともいいます。
それでは、早速学生クラスを作ってみましょう。クラスの名前はStudentとします。作り方はPersonクラスの時と同じです。Personクラス作成時と異なる点は、クラス名を入力する画面で、[Class]に「Student」、[Subclass of]に「Person」を入力します。
Studentクラスを作成したら、Student.hを開いてみましょう。
#import "Person.h" @interface Student : Person @end
「@interface Student : Person」とありますが、これが「学生クラスは人間クラスを継承する」ということを意味しています。
ところで、学生は学校名、学科、学年などさまざまなメンバー変数を持つことが考えられると話しました。ここでは、学校名を定義するメンバー変数を持つこととします。
Student.hとStudent.mを以下のように変更します。
#import "Person.h" @interface Student : Person { // 学校名 NSString *_school; } // 学校名を取得する - (NSString *)school; // 学校名を設定する - (void)setSchool:(NSString *)school; @end
#import "Student.h" @implementation Student // 学校名を取得する - (NSString *)school { return _school; } // 学校名を設定する - (void)setSchool:(NSString *)school { _school = school; } @end
Studentクラスを変更したら、ViewController.mを以下のように変更します。
#import "ViewController.h" // Studentクラスをインポートする #import "Student.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Personクラスのインスタンスを生成する Student *yuki = [[Student alloc] init]; // 性を設定する [yuki setLastName:@"平井"]; // 名を設定する [yuki setFirstName:@"祐樹"]; // 学校名を設定する [yuki setSchool:@"アイティメディア学園"]; // 名前と学校名をコンソールに表示する NSLog(@"こんにちは、私の名前は%@です。%@に所属しています。", [yuki name], [yuki school]); } @end
実行すると、以下のようにコンソールに表示されます。
このように、StudentクラスはPersonクラスを継承しているため、Studentクラスに定義されていない名前に関するメンバー変数やメソッドを使用できます。
Copyright © ITmedia, Inc. All Rights Reserved.