1. HOME
  2. テックブログ
  3. プログラミングのわかり方 vol.2

プログラミングのわかり方 vol.2

前回、プログラミングのミクロな部分に注目して、プログラミング=メモリ操作を指示するものだという説明をしました。また、このミクロな部分にのみ注目していても、それだけではゲームなどのアプリケーションを作ることはできないと書きました。今回は、このミクロな操作をどの様に紡いで大きなものを作っていくのかという部分を紹介していきます。

前回の記事はこちら→プログラミングのわかり方 vol.1

コンピュータを操作するとは、メモリを操作して(電気的なそろばんを弾いて)その結果を出力させることでした。では次に、その様な操作を組み合わせて、もっと複雑なアウトプットを作りたいと思うならば、つまりある課題をどの様にメモリ操作で表現するのか?ということを考えなければなりません。

「オブジェクト指向」という思想

これをうまく考えるには複数のアプローチがありますが、今まだ主流なのは「オブジェクト指向」と呼ばれるものです。オブジェクト指向は設計を含めたプログラミング全体をうまくやるための思想です。もう少し平たく言えば、プログラミングや設計の対象になるモノを「オブジェクト」と呼ぶ単位で考えて、そのオブジェクト同士のインタラクションによって全体の処理を実現すると良いのでは?というアイデアです。

ではオブジェクトとは何かというと「あるデータと、そのデータに対する処理」のセットとして定義されるものです。あるオブジェクトが定義されると、それと同時に、もう一つ客観的な観点では、あるオブジェクトの振る舞いが規定されることになります。

英語のセンテンスに「S:主語」と「V:術語」が必要であることからもわかる様に、あるモノ(S)とそのモノの振る舞い(V)、というのは人が記号をベースに物事を考えたり、他者とコミュニケートする際の基本型になっています。そのため、逆説的ではありますが、オブジェクトは自然に思考やコミュニケートの対象として扱いやすいものになっています。この様な考えやすく、コミュニケーションしやすい単位で部分を作っていき、それらを組み合わせて全体を作ろうということですね。

どんなものか見ていただいた方が速そうなので、擬似のコードを書いていきます。

モンスターの登場するゲームを考える

ここではゲームのプログラムを作っていて、そこに登場するモンスターを定義しようとしていると思ってください。全てのモンスターは今いる位置を表す座標と体力と攻撃力、スピードという属性値を持っているものとします。また少なくとも「移動する(move)」という能力を持っているものとしましょう。

以下は単なる例なのでコードの内容がわからなくても問題ありません。

class Monster{
        constructor(_x:number,_y:number,_hp:number,_atk:number,_sp:number){
            this.x = _x;
            this.y = _y;
            this.hp = _hp;
            this.attack = _atk;
            this.speed = _sp;
        }
        move = (map:Map,dir:Direction)=>{
            return map.move(this,dir);
        }
    }

ここではxやy、hpやattackやspeedといった属性値(データ)と、moveという動作に関する記述が確かに書かれているな…と言うところの理解でOKです。

ゲームではモンスターと、ユーザの(正確にはユーザが操作するキャラクターの)インタラクションの質が課題になっていきます。そこで、モンスターを画面に描画して動かすのですが、そのためにはモンスターの実態をメモリ上に展開する必要があります。

定義されたオブジェクトをメモリ上に展開することを「インスタンス化」と言いますが、ここでは次の様なコードで表現します。

 let monster1 = new Monster(5,5,30,10,3);

前回に、次のようなサンプルコードを書き、そしてこの様なコードを実行すると「a」というラベルが指す先のメモリ上に「101」というスイッチのセットができるということを説明しました。

 let a = 5;

上のモンスターのインスタンス化も似た様なもので「monster1」というラベルが指す先に「101」よりはずっと複雑な、monster1を表現するスイッチのセットが作られているのです。

この様にメモリ上に展開されたものは、それはもう概念ではなく、物理的な対象ですから具体的な操作が可能になりますね。例えば、このモンスターを右に一つ動かそうと思えばモンスターの左右位置を表すデータに+1を行う様にメモリを書き換えられれば良いですね。

まずモンスターという概念を考え定義し、次にそれを表現しているものが物理的にメモリ上にある様にしました。そして今、それを動かしたければどうすれば良いのかが明確になっています。この様なプロセスで必要なものをたくさん作って、それぞれがインタラクションする様に処理を付け足していけば、巨大で複雑なものもプログラミングできるという訳です。

以上で「プログラミングのわかり方」としては必要なことをお話しできたかと思います。

より理解を深めてみよう

ここからは主なトピックからは少し離れますが、せっかくモンスターのサンプルコードを書きましたのでオブジェクト指向についてもう少し理解を深めてみたいと思います。

先ほど、オブジェクトは「データとそのデータの処理方法」として定義されると書きましたが、それだけでなくオブジェクト同士の概念的な包摂関係も定義に利用できます。つまり「SならVできる」というときに「S’はSである」ことがわかっていれば「S’はVできる」はずです。このようなS’の性質をオブジェクトで表現することが、S’はSのサブセットだということで定義を始めることで可能になります。このこととメモリの関係を理解していくと現代の実践的なオブジェクト指向プログラミングの理解がより深められます。

***

ではまたコードから始めてみましょう。別のタイプのモンスターを考えてみます。先ほど定義したモンスターと同様の属性・能力を持ちながら、火の玉を打つ能力が付加されているものです。次の様になります。

    class FireBallMonster extends Monster{
        constructor(_x:number,_y:number,_hp:number,_atk:number,_sp:number,_gas:number){
            super(_x,_y,_hp,_atk,_sp,_gas);
            this.gasoline = _gas;
        }
        fire = (dir:Direction)=>{
            let fireball = new FireBall(this);
            if(fireball) fireball.letgo(dir);
        }
    }

例によって、コードの内容が理解できなくても問題ありません。ここで注目していただきたいのは、上記のコードの「extends Monster」と言うところです。これは、FireBallMonsterはMonsterが拡張されたものであって、Monsterの全ての属性と機能を持つという宣言です。そして、その上で「gasoline」という属性値と「fire」という動作が付加されているのです。そのため、概念的には全ての「FireBallMonster」は必ず「Monster」です。図で書くと次のようなものです。

上で概念の包含関係でオブジェクトを定義できると書きましたが、これがその具体例です。FireBallMonsterの定義の中にmoveという振る舞いの記述はありませんが、FireBallMonsterはそもそもMonsterの拡張ですので、Monsterが持っているmoveという振る舞いには対応できます。

さて次に、このFireBallMonsterをインスタンス化することを考えます。

let monster2 = new FireBallMonster(7,7,30,10,3,20);

これまでの例と同様に、メモリ上のmonster2のラベルの指す先にモンスターの実態を示すスイッチのセットが展開されました。ここで、monster1が展開されたものと、monster2が展開されたメモリを比べてみることにしましょう。monster2は、FireBallMonsterなので、Monsterよりも情報(gasoline)や機能(fire)が増えています。その分、メモリを多く利用しないと表現できないことがわかりますでしょうか?そして、先ほどの図と、メモリのサイズを見比べると次のことが分かると思います。

概念として小さいものは、メモリサイズとしては大きい

これは、まあ当然のことですよね。あるものを詳細に描写するほど、その描写にかかる情報量は多くなるのですから。では逆にメモリサイズとして一番小さなものは概念として一番大きいのか?という疑問が湧いてきますね?これはYESです。

オブジェクト指向プログラミングの世界ではこの「概念として最も大きい(メモリサイズとして最も小さい)」ものを「オブジェクト」と呼び、プログラミングに登場する要素の最上位の抽象概念として考えます。そして全ての要素はこのオブジェクトに含まれるため、オブジェクトなのです。

まとめ

プログラミングのわかり方について考えてきました。前半はプログラミングは結局メモリの操作というところからスタートして、後半はオブジェクト指向はこのメモリ操作をどの様にラッピングしているのか?を紐解いていくことで、概念的になりがちなプログラミングという行為の説明を試みたものです。

「オブジェクト指向」という概念は、実際にはこれだ!という定義が無いため、各々が好きに解釈可能です。とはいえ、ここでの説明には便宜的なものも含まれていますので、これで興味を持たれた方は是非調べてみてください。面白い話がたくさん見つかると思います。

この記事を書いた人

大西 秀典
プロダクト開発本部 IT戦略統括部長兼CDO
大西 秀典

おすすめの記事