初めに
こんにちは、今回はプログラミングの基本とも言えるオブジェクト指向ですが、
自分の言葉でオブジェクト思考とは何かを表現することによって、
さらに理解をブラッシュアップしていければいいなと思い、この記事を作成しました。
オブジェクト指向に対する解説記事はもう多く出回っている状況ですが、
どなたかにこの記事がお役に立てば幸いです。
オブジェクト指向とは
とあるデータとそのデータを制御する処理をひとまとまりのオブジェクト(物)とみなし、
そのオブジェクト同士の関係性を構築していくことで一つの成果物を作成していくプログラミング手法のことを指します。
オブジェクト指向を支える要素たち
オブジェクトを生成するための設計書のようなもの。
クラスの中には、それぞれプロパティとメソッドが要素としてある。
オブジェクトが保有するデータのことを指す。
オブジェクトが保有するデータ(プロパティ)を制御する処理のこと。
以下はHumanというクラスに、
それぞれプロパティとメソッドが配置されている例です。
class Human {
final int height; //身長
final int weight; //体重
final int age; //年齢
final String gender; //性別
// コンストラクタ
Human({required this.height, required this.weight, required this.age, required this.gender});
//上記は全てプロパティ
//以下は全てメソッド
void eat() {
print('美味しい');
}
void sleep() {
print('すやすや');
}
void work() {
print('早く帰りたい');
}
インスタンスとは
上記でクラスが何を指すかはある程度理解できたかなと思いますが、
クラスとはあくまで設計図でしかありません。
実際にクラスをもとにオブジェクトを生成するには、
クラスをインスタンス化(実体化)をする必要があります。
ここでは、上記で提示したHumanクラスのインスタンスを作成して、
オブジェクトを作成していこうと思います。
final yamada = Human(height: 175, weight: 70, age: 30, gender: '男性');
final sato = Human(height: 155, weight: 50, age: 20, gender: '女性');
final kobayashi = Human(height: 170, weight: 57, age: 24, gender: '男性');
yamada.work;
sato.work;
kobayashi.sleep;
上記の例では、それぞれ、yamada,sato,kobayashiという変数に、
Humanクラスのインスタンスを渡しています。
体重、身長、年齢、性別をコンストラクタに渡すことで、
インスタンスの作成時にそれぞれ別の値を渡すことによって、
違ったオブジェクトを作成することができます。
こうしてクラスをインスタンスした物を変数に格納することで、
クラスのインスタンスを簡単に扱えるようになります。
オブジェクト指向の3つの原則
そもそもなぜこのようなオブジェクト指向に準拠した手法が推奨されているかというと、
以下のような原則があり、
その原則を守ることによって、多くのメリットを享受できるからです。
クラスのプロパティとメソッドを再利用するための仕組み。
今回の例でいうと、すでにHumanクラスを作成しています。
そのクラスをもとに山田さん、佐藤さん、小林さんのインスタンス(実体)を作成しています。
さらに加えて、山本さんのインスタンスを作成することになったとしましょう。
しかしここで問題が発生しました。。
まさか、山本さんは、仕事もろくにせず、
寝食の時間を削ってまでお酒を飲みまくるとんでもないアル中だったのです!!!
(全国の山本さん本当にすいません)
ですが、アル中以外の特徴は、
他の方と違いありません。
コードを再利用するためにもHumanクラスを継承し、Humanクラスを一部再利用した、
DrunkerHumanクラスを作成します。
class DrunkHuman extends Human {
DrunkHuman({required int height, required int weight, required int age, required String gender})
: super(height: height, weight: weight, age: age, gender: gender);
// Humanクラスからメソッドを継承している
@override
void eat() {
print('飯買うお金あるんなら酒飲みたいけどね');
}
// Humanクラスからメソッドを継承している
@override
void sleep() {
print('寝る時間あるんなら酒飲みたいけどね');
}
// Humanクラスからメソッドを継承している
@override
void work() {
print('酒飲むのが仕事です');
}
//DrankHumanのユニークなメソッド
void drinkAlcohol() {
print('え、これ度数低くない??');
}
}
}
Humanクラスを継承したDrunkHumanクラスをインスタンス化してみましょう。
final yamamoto = DrunkHuman(height: 175, weight: 120, age: 30, gender: '男性');
yamamoto.eat();
yamamoto.drinkAlcohol();
新たに、DrunkHumanクラスを作成することにより、
今後新たな酒乱が誕生した際にも簡単にアル中人間を作成することができます。(?)
詳しい継承の仕組みや方法に関しては以下の記事も参考にしてみてください!
実際の実務では、複数人と同時に作業することもありますし、
実際の商業用アプリでは、多くのクラスが定義されており、
色々な変数が複数の状態を持っており、開発者が意図しない状態で
変数などが変更されてしまうバグが発生してしまうことがあります。
そこで変数や関数を、クラスとして覆うことで、
他のクラスから意図せず使用されてしまうことを防ぐ目的があります。
ポリモーフィズムとは日本語では多態性などの意味になるそうです。
クラスに宣言されているメソッドの振る舞いを自由に変更できることを指します。
今回の例でいうと、山田さん、佐藤さん、小林さんは、
void work() {
print('早く帰りたい');
}
というメソッドを持っていましたが、
かたや山本さんは
@override
void work() {
print('酒飲むのが仕事です');
}
同じworkという関数ですが、
printの中身が違いますよね。
このようにオーバーライドなどを活用して同じメソッド名でも異なる振る舞いを実現可能にしていることをポリモーフィズムと言います。
参考記事
最後に
最後までご覧いただきありがとうございました。
何かご指摘等あればコメントいただけると幸いです。
それと、全国の山本さん勝手にアル中に仕立ててしまい本当にすいません、他意はありません。。