次に、記事「オブジェクトに必要な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.