クラスとインスタンスとちょっとオブジェクト指向を理解

オブジェクト指向

こんにちはカイリーーです。

今回は、クラスとインスタンスを理解するために僕自身が参考にした資料をまとめました。

「オブジェクト指向」というとかなり大それた話になりそうなので(というより、完璧に理解した、の域に達しているわけではないので、あえて、こういう言い方にとどめています)、「クラス」と「インスタンス」と「ちょっとオブジェクト指向」にとどめました。

このクラスやインスタンスまたオブジェクトはSESで勤め始めたときは、全く理解できませんでした。

当時、クラスを見たときはこんな思いでした。

カイリーー

なんでわざわざクラスなんか使って、あっちいったり、こっちいったり、わけわかんない書き方するんだよ。

このときはクラスに分けるメリットもわからなかったため、こんなことを思っていましたが、クラスで書かれている以上、これを理解しないことには話にならない。

そんな思いで資料をあさってあさって読み漁った資料でお世話になった資料を厳選しました。

この記事の対象読者

  • クラス・インスタンスってなに?
  • クラスを使いたいけど意味がわからない
  • 僕のように使わざるを得ない状況になってしまっている方
  • どうせやるならクラスを理解したい

おすすめしない人

  • プログラミングをはじめて間もない人
  • クラス等を特に必要としていない人

そもそもクラスとは何なのか?メリットは?

クラスを使う目的やメリットがいまいちわからない。

そんな方が多いと思う。

使わなくても動けば良いのではないか。

いや、極論問題なく動けば良いとは思う。

しかしここで、考えてみてほしい。

ぐちゃぐちゃになった部屋、平積みされた本のタワーがあるとする。

ここからONE PIECEの30巻を探してください。

といわれたら、すぐに取り出せるだろうか?

おそらく、あちこち探し回って、運良く見つかるか、見つかったとしてもかなりの時間がかかることが容易に想像できる。

プログラムにも同じことが言える、動けば良い、と思って作られたコードから出来たシステムやツールに仕様変更が生じた場合に、コードがぐちゃぐちゃになった状態のところから影響範囲を割り出して改修を加え、なおかつ、バグが出ないようにコードを書き換えるのは至難の業である。

それを解決してくれる役割の一つにクラスが存在する。

オブジェクト指向でつまづく7つのポイントと処方箋 – t-hom’s diary

こちらの記事で伊藤先生も書かれているように、この数年でVBAのクラスモジュールに関する情報が充実してきている。これからクラスモジュールについて学習しようと考えている方も沢山(期待を込めて)いらっしゃることと思う。そこで今回は、オブジェクト指向を学習するにあたってつまづきやすいポイントを紹介し、その処方箋としてアドバイスを書いてみようと思う。私がオブジェクト指向でつまづきやすいポイントは以下の…

こちらの記事でも紹介されている通り、

オブジェクト指向とはコードを整理整頓する技術であり、それが根本の目的と言っても過言ではない。

オブジェクト指向でつまづく7つのポイントと処方箋

そう、コードを整理整頓してメンテナンスしやすくするのが、クラスの役割である。

昔々、1960年代ごろに手続き型プログラムと言われる、全ての手続きからアクセス可能なグローバル変数の集合体によって構成される手続き型プログラムの構成で、どこから参照され、どこを変更しなければいけないのか?といったことからバグの温床になることが問題となった「グローバル変数問題」などが指摘され、後にオブジェクト指向という考えが提唱された。

過去をたどっていくと、そういった経緯もあり、クラス(オブジェクト指向)という考えによって色々と見直された。

このクラスを使うことで、どこからでもアクセス可能だったグローバル変数を、どこからでもアクセス出来ないように、クラスの中で定義した変数に、ある書き方をしない限り、クラスの中の変数にアクセス出来ないように制限を設けたりした。

上記をすることによって、どんなメリットがあるのかというと、先に述べた、「どこからでも参照され、どこを変更したのかの影響範囲がわからない

これを解消できる。

要するにバグの温床を最小限に留めることができるのだ。

ではクラスってどうやって使うのか?

おそらく、次に出てくる言葉はこうだと思う。

カイリーー

なるほど。クラスを使うメリットはわかった。ではどうやってこのクラスを使えば良いのか?

本ブログの読者さん(あまりいないかもしれないが)は、カイリーーはVBAやGASに関する記事を書いていると思っているだろうから、GASでの使い方をまとめてみたいと思う。
VBAのclassについては以下記事を参考に実際に書いてデバッグして動作確認していただくと良いかと思います。

VBA クラスモジュール 超 入門 – t-hom’s diary

このブログではこれまでにクラスモジュールを活用したコードをいくつか紹介してきたが、 使いどころの紹介がメインでクラスモジュールそのものの 使い方 について一から学べるような構成は取っていなかった。 今回は「クラスモジュール超入門」と題してクラスモジュールを初めて使う方やオブジェクト指向がいまひとつ分からないという方に向けて解説してみようと思う。 …

書き方の前にクラスの概念についてもう少し説明させてほしい。

クラスとはよく様々な「物体」の設計書やひな形、などと言われる。

これだけだと、ちょっと何言ってるかわかんない。

オブジェクトとは「物」物体を表す。

クラスとは「設計書」を表す。

「物」を生み出すためには「設計書」が必要です。

これで少しわかりやすくなったか。

では、ちょっと例えを変えてみます。

突然ですが、ミニ四駆を組み立てるには何が必要でしょうか。

ニトリで買った家具を組み立るには何が必要でしょうか。

答えは「説明書」

一つのミニ四駆(プラモデル)や家具を組み上げるには、「説明書」が必要であり、それを組み上げて作られたのが「物」だ。

設計書から説明書に言葉が入れ替わっているじゃないか、と思われたと思うが、世間一般に使われているものの方がしっくり来ると思い上記を例として説明させていただいた。

ミニ四駆(プラモデル)もニトリの家具も、それぞれパーツが存在し、それを説明書を見ながら組み立てていく。

そんなイメージをしていだいていただければと思う。

クラスを理解する上で、必ず必要になってくるのが、

プロパティとメソッド。

わかりやすく言うとプロパティは変数

メソッドは関数

と思っていただくと良いかと思います。

プロパティとは属性や情報

メソッドは動作や振る舞い(物の動き)

などと言われています。

では、ミニ四駆におけるプロパティとは?メソッドとは?

以下のように定義してみました。

プロパティ

  • 名前
  • 重さ
  • スピード

メソッド

  • 走る

まとめると

ミニ四駆というクラスを定義し、

そのミニ四駆はどんな情報を持ってるのか?

どのような動作や振る舞いをするのか?

それが、プロパティ(変数)とメソッド(関数)で表すことが出来ます。

実際にプロパティに情報をいれてやるとこんな感じになると思います。

プロパティ

  • 名前 = サイクロンマグナム
  • 重さ = 200g
  • スピード = 20km

メソッド

  • 走る ()

GASクラスにおける基本構文は以下のようになります。

class クラス名 {
   constructor(引数)
      this._変数 = 引数
   
   関数名(){
   
   }
}

constructorとはクラスをnewしたときに自動的によびだされて実行されるメソッドです。

VBAでいうinitializeです。

「this.」というのは、thisとは自分自身を指すであったり、
thisキーワードは、その関数・メソッドとプロパティとして持つオブジェクトへの参照です。

などと書かれているものがあるのですが、ちょっとむずかしい。

あくまで僕がthisを日本語化した場合は

このクラスのプロパティは○○です。

そのプロパティにAという変数の値を代入します。

そしてそのプロパティの値を使う場合には、this._変数とすることでプロパティ値を参照することが出来ます。

と解釈しています。

メソッドを参照する場合も同じです。

このthis問題の説明がなかなか難しいですが、自分なりにしっかり理解して解釈するとしたら上記のように考えるようにしています。

ここまで説明して、先程の基本構文に日本語で定義していたプロパティ値を設定し、走る動作を当てはめると以下のようになります。

class Mini4wd {
	constructor(machineName, weight, speed) {
    //プロパティ値(情報)
		this._name = machineName; //名前
		this._weight = weight; //重さ
		this._speed = speed; //スピード
	}
	//走るという動作
	machineRun() {
		return this._name + "は" + "時速" + this._speed + "km" + "で走ります。"
	}
}
function main () {
	const machineName = "サイクロンマグナム";
	const weight = 200;
	const speed = 20;
	const magnum = new Mini4wd (machineName, weight, speed);
	console.log(magnum.machineRun());
	//結果:サイクロンマグナムは時速20kmで走ります。
}

処理の流れは以下の様になります。

このメイン処理とクラスを見てもらうと分かる通り、

クラスはミニ四駆に関する「情報」と「動作」の内容が記載されています。

このミニ四駆クラスから生み出された具体的なサイクロンマグナムがインスタンスとなる。

ミニ四駆の設計書(説明書)から、サイクロンマグナムという物体を生み出した。

もちろんミニ四駆クラスからは別のインスタンスを生み出すことができる。

例えばハリケーンソニックをインスタンス化しようとすると以下のようになる。

let machineName_2 = "ハリケーンソニック";
let weight_2 = 200;
let speed_2 = 15;
const sonic = new Mini4wd_2 (machineName_2, weight_2, speed_2);

このmagnumやsonicなどの具体的なミニ四駆の定義がインスタンスとなる。

厳密には、値の妥当性をチェックするために、以下のようにチェック機能を働かせる必要もあります。

class Mini4wd_2 {
  // プロパティ値(値のセット)
	constructor(machineName, weight, speed) {
    try {
      // 車体重量がマイナスの場合エラー
      if (weight <= 0) {
        throw new Error("車体重量がレギュレーション違反です");
      } else {
        this._name = machineName; //名前
        this._weight = weight;//重量
        this._speed = speed; //スピード
      }
      }catch(e){
        Browser.msgBox("エラー:" + e.message);
      }
	}

if (weight <= 0)として0以下はありえないので、その場合はレギュレーションに違反している旨の例外エラーを発生させています。(余談:公式のミニ四駆のルールの重量は90g以上である必要があるようです)

1g以上であれば、プロパティ値に格納できる。(本来1gもありえないが、例のため、0g以下の場合は、という仕様にさせていただいた。)

このような仕組みにすると何が良いのかというと、クラス宣言をした入り口で異常値を検知し、エラーで止めることができるというメリットがある。

例えば、テキストボックス等でユーザーに入力をしてもらうようなシステムの場合、意図的にマイナスの値を入れられることを考慮すると、プロパティの値をセットする前にバリデーションを働かせて異常値を検知させる必要があります。

ここまでクラス、インスタンス、プロパティ・メソッドについて説明してきました。

あくまでこの記事はクラスを定義して使用する上での最低限の内容について記述しています。

上記内容をエヴァを使ってJavaを使って、スレッドのやり取りでオブジェクト指向について説明している掲示板が以下です。

Javaのオブジェクト指向をエヴァで例えると超わかりやすい : IT速報

安価でプログラミングをするスレより。このスレは1さんと2さんが主に会話をしています。Javaについての会話がとても有意義だったのでまとめてみました。挫折ポイントとして名高いオブジェクト指向も、このようにエヴァで例えるとすんなりと理解できそう! 1さんが2さんにJavaを教えるところからスタートします。 ちなみにけっこう長めのまとめ。Javaに興味ある人、Javaをお勉強中の人は何度か読み返すといいかもしれません(*・ω・*) どこまでできる? 111: 2◆DTn7LrZ..DaI 2014/04/05(土)01:08:06 ID:XKWkZFm7A 何をだい?? java 113: 2◆DTn7LrZ..DaI 2014/04/05(土)01:09:49 ID:XKWkZFm7A 数値入力して計算して表示・・・ クラスのお話しする?俺もよくわからんけど 115: 2◆DTn7LrZ..DaI 2014/04/05(土)01:11:31 ID:XKWkZFm7A クラスのお話か~理解できるか心配w class Tmp{int val;public void method(){//処理}} ————————-こんな「Tmp」というクラスがあったらTmp obj = new Tmp();//newを使ってインスタンスを生成して obj.val = 50; //クラスの中身にアクセスするにはクラス名のあとに.を付けるobj.method(); 117: 2◆DTn7LrZ..DaI 2014/04/05(土)01:16:32 ID:XKWkZFm7A (;゚Д゚) もう一回エヴァで説明してみるよ 122: 2◆DTn7LrZ..DaI 2014/04/05(土)01:21:37 ID:XKWkZFm7A はい、お願いします 124: 2◆DTn7LrZ..DaI 2014/04/05(土)01:27:10 ID:XKWkZFm7A

あくまで概念を理解するものであるため、オブジェクト指向とは?の部分をスキマ時間の読み物として読んで頂くと良いかと思います。

そして、次にご紹介する記事が僕がクラスを理解する上で、何十回と読み直した記事です。

【PHP超入門】クラス~例外処理~PDOの基礎 – Qiita

2021 年 10 月 8 日に Udemy で「プログラミング学習の心得&HTTPの基礎」の動画講座を公開しました。 特別に 85% OFFのクーポンを発行します。 通常価格 10,800 円が 1,610 円で購入できます。 動画内でも説明していますが、初心者・初学者向けの内容です。 事前に自分の知りたい内容・興味のある内容か確認してからご購入ください。 変数と関数の基礎はわかり、クラスも何となく聞いたことがある超初心者向けです。 長いですが、変数と関数しかわからなくても、読めばクラス、例外処理、PDOについて何となくわかるようになると思います。 それ以上の方は、読む必要はないと思います。 時間の無駄ですwww PHPでデータベースを利用するには、PDOを理解する必要があります。 PDOを理解するには、クラスと例外処理の基礎知識が必要になります。 プログラミングの経験もなく、PHPを勉強し始めた超初心者にとっては非常にハードルが高いです。 なので、PDOを使ってデータベースに接続するために という流れでまとめてみました。 データベースへの接続方法の一つにmysql関数を使った方法があります。 下記のように関数を使い引数を指定するだけで簡単に接続できました。 すげー簡単!やったー\(^o^)/ って感じですが、mysql関数を使った接続方法は、PHP 5.5.0 で非推奨になり、PHP 7.0.0 で削除されました。 特別な理由がない限りこの接続方法は使わないようにしましょう。 mysql関数以外でデータベースに接続するには、PDOまたはMySQLiを使用します。 今回は、PHP5.1.0から使えるPDOを使ってデータベースに接続したいと思います。 早速、PDOを調べてみると データベース抽象化レイヤの一つで、プリペアドステートメントを … えっ … 抽象化レイヤ? プリペアドステートメント? なにそれ …

こちらの記事では序盤、

クラスとは変数と関数の集まりであり、データの「保持」と「処理」が可能

とおっしゃってます。

簡潔にまとめるとそうだと思います。

それが、クラス内では変数のことを「プロパティ」と呼び、

関数のことを「メソッド」と呼んでいます。

もう一度GASのクラスの基本構文の見てみましょう。

class クラス名 {
   constructor(引数)
      this._変数 = 引数
   
   関数名(){
   
   }
}

クラス内で書かれているものなので、記事の通り呼び名を変えてみましょう。

class クラス名 {
   constructor(引数)
      this._プロパティ = 引数
   
   メソッド(){
   
   }
}

こうなります。

これがいわゆる設計図の基本の型となります。

main()の処理でconst magnum = new Mini4wd();

とすることでマグナムのインスタンスが作られ、magnum. メソッド()

とすることでクラスへアクセスし、プロパティ、メソッドを扱って処理を行います。

magnum. メソッド()とは「マグナム」の「処理」を指しています。

こちらの記事にオブジェクト指向のコードを書く上での基礎が集約されています。

言語はPHPですが、PHPは比較的理解しやすい言語なので、この記事の言っている内容がある程度理解できるようになれば、VBAでのクラスにおいても理解の手助けになるかもしれません。

僕の場合、VBAのクラスがどうしても初め理解できず、別言語でわかりやすく説明されている記事はないか?と思いたどり着いたものがこちらでした。

もちろん理解するためには、別言語でも書いてコードを実行して、処理の流れを追うことで理解のスピードも早くなると思っています。

ぜひ一読、いや、何回も読んでいただければと思います。

メモリーの話

最後にメモリーの話をしておきたいと思います。

基本的なPCの仕組みはメモリーとディスクの関係性にあります。

ディスクに記憶されたプログラムがメモリーにロードされてから実行されます。

図にすると以下のような感じです。

ではこれが一体クラスと何の関係があるの?

その関係性ついては以下の動画を御覧ください。

【エンジニア Q&A #03】クラスとインスタンスの違い:無職の学び舎

◆エンジニア Q&Aネットで見かけたエンジニアの疑問に勝手に答えるシリーズクラスとインスタンスの違いについて解説クラスは設計図って例えられるけどそもそもなんで設計図って例えられるの?というお話————————————————————-…

クラスを定義すると、クラス内に記述された情報を保持するために、どの程度のメモリーを確保しなければならないのか?

実際に確保された「物」=メモリそのものがインスタンスである

C言語を書いたことがない僕は、このメモリを意識してクラスを書いていなかったのですが、実際には、ハードディスクからプログラムがロードされ、どこの番地に必要な分のメモリを確保する処理が行われている、というのを理解しておく必要がある。

また、上記の動画を見た上で次の記事を読むと、言っていることの理解が進みます。

VBA 変数とメモリの関係 ~ 値渡しと参照渡しをメモリの動きから理解する – t-hom’s diary

今回は変数とメモリの関係について書こうと思う。 ちょっと「記号表」とかいろいろ難しいモノが登場するのだが、ちょっとわかりやすく説明するためにしておこうと思う。 まずあなたが VBAコードを書く。 すると、1行確定させるごとに コンパイラー君が間違ってないかチェックする。 もし間違いがあったらその都度あるいは実行前に コンパイラー君に注意される。 これがいわゆる コンパイル エラー。 問題なければ、 コンパイラー君はPコードという中間コードを生成する。 Pコードは我々が目にすることはないが、 VBA コードを圧縮して実行効率をアップさせたようなものだと思えば良い。 これを今度は VBA インタープリターさんが一行ずつ読んで順次実行していく。 これがいわゆる実行時エラー。 さて、まとめると VBAのプログラムはこのような連携で動いているということになる。 ただし、 コンパイラーが挟まると話がややこしくなるのでここで コンパイラー君とはお別れ。 以降は インタープリターさんが直接 VBA コードを読むという設定で話を進める。 VBA で次のようなコードを書いたとする。 単純な変数宣言と値の代入であるが、これを実行したとき、内部では何が起きてるんだろうか。 まず インタープリターさんがメ モリーから2バイト確保する。 それから インタープリターさんは確保したメモリに初期値のゼロを格納し、変数名とアドレスの対応付けを「記号表」に書き込む。 この記号表というのもメモリ上のどこかにあるのだが、 インタープリターさんが管理しているので我々 プログラマー は普段意識することはない。 さて、次がa=10。このとき インタープリターさんは記号表からaを探し、その番地を確認する。 そして次のように色々な型で宣言すると、 ローカル変数の場合、スタックメモリという領域に保存されるのでメモリ番地は下から順に埋まっていくのが特徴である。 プロシージャ呼び出しの際にパラメーターを渡す場合、値渡しと参照渡しの二種類がある。 呼び出される側のプロシージャでByValキーワードを使えば値渡しとなり、何も書かないか、ByRefと書けば参照渡しになる。これもどういうことなのか図で説明しよう。 まずは値渡しのケース。 さて、ここでプロシージャBをByRefに書き換えてみる。 以上が値渡しと参照渡しの内部動作の違いである。 今回はホントはオブジェクト変数とメモリの関係について書きたかったんだけれど、その前提として基本型変数でのメモリの動作を説明しておかないとなんのことかわからなくなるのでいろいろと書いてるうちに力尽きた。 オブジェクトの場合はまた今度にしよう。。 なお、厳密にいえば今回説明したメモリアドレスは実際は物理メモリアドレスではなく、OSによって管理されたプロセスごとの 仮想メモリ 空間のアドレスである。ツッコミがあるといけないので一応最後に補足しておいたが、これを語りだすとまた長くなるのでとりあえず便宜的にはメモリアドレスだと思ってもらって良い。

VBA オブジェクトとメモリの関係 ~ オブジェクトが参照型と呼ばれる理由 – t-hom’s diary

前回、 VBA を擬人化して、変数が記号表によって管理されているというところまで書いた。 さて、今回はオブジェクトがメモリ上でどう扱われるのかという話。 次のコードで説明しようと思う。 前回の話では、値がメモリに入っていて、記号表によって変数名とアドレスを対応付けていると説明した。 …

カイリーー

正直なところ、このメモリの概念については僕自身まだまだ理解・研究がしきれていないため、今後の課題です。
こちらの方々が説明されているようなレベルに達するまでは、もっと深堀りして行く必要がありそうです。

今回の記事はここまでです。

ここまで読んでいただきありがとうございました。

ご意見ご感想ございましたら、TwitterDM等でお知らせいただければと思います。

\無料コンテンツを配布しております/

毎日エンジニアとして勉強をしているのに

  • コードが読めるようにならない
  • コードを書くなんてもってのほか
  • 環境構築ができない(そもそも何をやっているのかわからない)
  • >毎日できない自分に嫌気が差す

そんな毎日に悩みを抱えている方

もしかしたら間違った勉強方法をしているかもしれません。

エンジニアとして生きていくための正しい勉強とは
一体何でしょうか?
以下からご確認ください

コンテンツ無料ダウンロードページ

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です