オブジェクト指向においてもう一つ重要な概念があります。それは「ポリモーフィズム」です。日本語では「多態性」「多様性」と訳されることが多いです。これはどういうことでしょうか。
例えば、先生というクラスを考えてみましょう。先生はもちろん人間で、担当するクラスや授業といったメンバー変数を持つことが考えられます。先生クラスも学生クラスと同様、人間クラスを継承することになるでしょう。
またViewControllerクラスでは、まるで自己紹介するように、コンソールにログを表示していました。これを新たにPersonクラスのメソッドとして定義してみましょう。メソッドの名前は「- (void)introduceMyself」とします。
まず、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; // 自己紹介する - (void)introduceMyself; @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]; } // 自己紹介する - (void)introduceMyself { // 名前をコンソールに表示する NSLog(@"こんにちは、私の名前は%@です。", [self name]); } @end
「- (void)introduceMyself」メソッドの中で[self name]というものがあります。これは自分自身のインスタンスにメッセージを送信し、nameメソッドを呼び出すということです。
次に、Studentクラスを変更します。Studentクラスでは学校名を定義しているので、自己紹介するときに学校名も紹介したいです。というわけで、Student.mを以下のように変更します。
#import "Student.h" @implementation Student // 学校名を取得する - (NSString *)school { return _school; } // 学校名を設定する - (void)setSchool:(NSString *)school { _school = school; } // 自己紹介する - (void)introduceMyself { // 名前と学校名をコンソールに表示する NSLog(@"こんにちは、私の名前は%@です。%@に所属しています。", [self name], [self school]); } @end
Personと同じようにStudentクラスでも「- (void)introduceMyself」を実装しています。このように、スーパークラスのメソッドをサブクラスで上書きできます。このことを「オーバーライド」といいます。
Studentクラスを変更したら、今度は新たに先生クラスを作成しましょう。クラスの名前はTeacherとします。作り方はもうお分かりですね。クラス名を入力する画面で、ClassにTeacher、Subclass ofにPersonを入力します。
Teacherクラスには、担当教科を定義するメンバー変数を持つこととします。また、自己紹介メソッドをオーバーライドして、自己紹介のときに担当教科を紹介するようにします。Teacher.hとTeacher.mを以下のように変更します。
#import "Person.h" @interface Teacher : Person { // 担当教科 NSString *_subject; } // 担当教科を取得する - (NSString *)subject; // 担当教科を設定する - (void)setSubject:(NSString *)subject; @end
#import "Teacher.h" @implementation Teacher // 担当教科を取得する - (NSString *)subject { return _subject; } // 担当教科を設定する - (void)setSubject:(NSString *)subject { _subject = subject; } // 自己紹介する - (void)introduceMyself { // 名前と担当教科をコンソールに表示する NSLog(@"こんにちは、私の名前は%@です。担当教科は%@です。", [self name], [self subject]); } @end
Teacherクラスを作成したら、ViewController.mを以下のように変更します。
#import "ViewController.h" // Studentクラスをインポートする #import "Student.h" // Teacherクラスをインポートする #import "Teacher.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Personクラスのインスタンスを生成する Student *student = [[Student alloc] init]; // 性を設定する [student setLastName:@"平井"]; // 名を設定する [student setFirstName:@"祐樹"]; // 学校名を設定する [student setSchool:@"アイティメディア学園"]; // 自己紹介する [student introduceMyself]; // Personクラスのインスタンスを生成する Teacher *teacher = [[Teacher alloc] init]; // 性を設定する [teacher setLastName:@"山田"]; // 名を設定する [teacher setFirstName:@"太郎"]; // 学校名を設定する [teacher setSubject:@"国語"]; // 自己紹介する [teacher introduceMyself]; } @end
この状態で実行すると、コンソールに以下のように表示されます。
ViewController.mのプログラムを見てみましょう。24行目と35行目で、それぞれStudentクラスのインスタンスとTeacherクラスのインスタンスの「- (void)introduceMyself」メソッドを呼び出していますね。
ここで、StudentクラスとTeacherクラスはともにPersonクラスのサブクラスであることを思い出しましょう。このViewController.mは以下のように書き換えることができます。
#import "ViewController.h" // Studentクラスをインポートする #import "Student.h" // Teacherクラスをインポートする #import "Teacher.h" @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 人間クラスのインスタンスを格納する配列を準備する NSMutableArray *persons = [NSMutableArray array]; // 学生クラスのインスタンスを生成する Student *student = [[Student alloc] init]; // 性を設定する [student setLastName:@"平井"]; // 名を設定する [student setFirstName:@"祐樹"]; // 学校名を設定する [student setSchool:@"アイティメディア学園"]; // persons配列にstudentを格納する [persons addObject:student]; // 先生クラスのインスタンスを生成する Teacher *teacher = [[Teacher alloc] init]; // 性を設定する [teacher setLastName:@"山田"]; // 名を設定する [teacher setFirstName:@"太郎"]; // 学校名を設定する [teacher setSubject:@"国語"]; // persons配列にteacherを格納する [persons addObject:teacher]; // 配列をループする for (Person *person in persons) { // 自己紹介する [person introduceMyself]; } } @end
41行目を見てください。それぞれStudentクラスのインスタンス、Teacherクラスのインスタンスとして格納していましたが、取り出すときはPersonクラスのインスタンスとして取り出しています。このように、サブクラスはスーパークラスのインスタンスとしても扱えます。このような関係をオブジェクト指向では「is-a関係」といいます。
また、43行目を見てください。ViewControllerのプログラムでは、StudentクラスなのかTeacherクラスなのかということは意識せずに- (void)introduceMyselfメソッドを呼び出しています。しかし、同じメソッドを呼び出しているにもかかわらず、実行結果はそれぞれ実装した内容になります。
このように、同じメッセージを送信しても、受信したインスタンスのクラスに応じて違う動作をすることを「ポリモーフィズム」と呼びます。この概念は非常に重要な概念ですので、ぜひ覚えてください。
本記事では、Objective-Cでのオブジェクト指向プログラミングの基本を解説しました。今回Personクラスの_name属性にアクセスするために- (NSString *)nameメソッドと- (void)setName:(NSString *)nameメソッドを定義しました。
実は、Objective-Cではもっと簡単にプロパティにアクセスする方法があります。というわけで、次回はプロパティとメソッドについて詳しく解説したいと思います。
Copyright © ITmedia, Inc. All Rights Reserved.