C#初心者によるC#のお勉強やろう10 オブジェクト指向編

勉強難しいです。el(える)です。

 

今回はオブジェクト指向について学んでいきます。

なんか難しそうな響きですが、頑張って覚えていきましょう。

オブジェクト指向とは

プログラムをまとめるための仕組みです。

オブジェクト指向は特定の文法を指した言葉ではなく、

 プログラムを書くときの考え方 のことです。

オブジェクト指向

プログラミングを始めたばかりの人や、大規模なプログラムを作ったことがない人には、

これらの便利機能(カプセル化、継承、ポリモーフィズム)が何の役に立つのか実感しにくいと思います。

これらの機能は 使うと楽が出来そうと感じたときに使えばいいもの で、

オブジェクト指向でプログラミングをするなら、

必ずどこかで使わなければならないというわけではありません。

まずは必須となる クラスとインスタンス をしっかりと理解しましょう。

オブジェクト指向の本質

オブジェクト指向とはクラスと呼ばれるまとまりで プログラミングを分割して整理する考え方 です。

メソッドという仕組みをつかって処理を分割しましたが、

プログラムの規模が大きくなると、メソッドを作るだけでは整理しきれなくなります。

規模の大きなプログラムを作るためにはもう少し大きい単位でプログラムをまとめる必要があります。

たとえば、流し台に鉛筆があったり、事務作業する机には洗剤があったりすると、混乱しますよね。

流し台にはスポンジと洗剤、作業机には鉛筆と消しゴムというように、

基本的に関連があるものを近くに置きます。

さらに、鉛筆や消しゴム、コンパスなどは 文房具と名前を付けた箱 に入れ、

スポンジや洗剤、たわしなどは 掃除用品と名前を付けた箱 にいれると整頓されます。

プログラムでも同じで、プレイヤの体力を表す変数や敵キャラを攻撃するメソッド、

ショップのアイテム情報などを1つのファイルにまとめるより、

プレイヤ関連、敵キャラ関連、ショップ関連のように、

それぞれ関連のあるもの同士に分けて書くと整理されて読みやすくなります。

 関連するもの(実際のプログラムでは関連のある変数とメソッド)をクラスという単位でまとめる考え方 をオブジェクト指向といいます。

クラスとインスタンス

クラスとは 関連のある変数とメソッドをまとめたもの です。

オブジェクト指向のイメージをつかむためにゲームを例に説明します。

ここではプレイヤが敵キャラを攻撃するゲームを例に考えてみます

クラスを作る手順

  1. アプリケーション内で変化する可能性のあるものを書きだす
  2. 書きだしたものそれぞれに属する値を列挙する
  3. 書きだしたものそれぞれに対応する動作や処理を列挙する

 

・アプリケーション内で変化する可能性のあるものを書きだす

アプリケーション内で 変化する可能性のあるもの を書きだします。

たとえば、位置や大きさ、向き、レベルなどが変化するものです。

ものを変化させるにはそのためのプログラムが必要になります。

今回の例ではプレイヤは動くものとみなせるので、

プレイヤクラス敵クラスをつくります。

書きだしたクラス:プレイヤ

・書きだしたものそれぞれに属する値を列挙する

 書きだしたものに属する値(パラメータ、性質など)はそのものと関連が深い値と考えられるので、クラスの変数として持たせます。 

プレイヤクラスに属する値として名前HPMPレベルなどが考えられます。

この中からプログラムで使用するものを変数にします。

また敵クラスに属する値も同様に名前HPレベルなどが考えられます。

・書きだしたものそれぞれに対応する動作や処理を列挙する

 書きだしたものに関する動作をそのクラスのメソッドとして持たせます 

プレイヤクラスに関する動作には物理攻撃魔法攻撃などが考えられます。

敵クラスに関する動作には攻撃逃走などが考えられます。

以上、3つの手順でプレイヤクラスと敵クラスを書きだすことが出来ました。

クラス

もう一つ、 プレイヤがショップで爆弾などのアイテムを買う場合 を例に、クラスの作り方を考えましょう。

・アプリケーション内で変化する可能性のあるものを書きだす

動くものとしてプレイヤ店員がみつかります。

爆弾のアイテムも爆発するという動作が必要なんでクラスにできます。

ショップという施設は店が動き出すことはありませんが、

お店のアイテムの在庫数や売り上げ情報などの値が変化するためクラスにします。

書きだしたクラス:プレイヤ店員爆弾ショップ

・書きだしたものそれぞれに属する値を列挙する

店員クラスに属する値には名前や年齢が考えられますが、

 店員の役割を考えると使う場面はなさそうなのでここでは変数にしません。 

ショップクラスに属する値は店の名前アイテムリストが考えられます。

爆弾クラスに属する値は値段爆発までの時間爆発の威力などが考えられます。

・書きだしたものそれぞれに対応する動作や処理を列挙する

店員クラスの動作には入店時のあいさつ売買の会話が考えられるのでこれらをメソッドにします。

ショップクラスに関する動作にはアイテムの販売アイテムの買い取りが考えられます。

爆弾クラスの動作には爆発が必要になります。

ショップ

01プレイヤクラスを作ってみよう

 変数に名前と体力、メソッドに攻撃と防御を持つプレイヤクラスを作ります。   コンソールに文字列で動作を表示する簡単なもの を作ります。

新規プロジェクトを作成します。

Visual Studioのメニューバーからファイル→新規作成→プロジェクトを選択。

ダイアロボックスの左側の項目からテンプレート→VisualC#→Windowsクラシックデスクトップを選択。

中央の項目からコンソールアプリ(.NETFramework)を選択。

プロジェクト名には「SampleRPG」と入力し、

プロジェクトの保存場所を任意の場所に設定してOKボタンをクリックしてください。

つづいてクラスを追加します。

Visual Studioの右側のソリューションエクスプローラーのSampleRPGの上で右クリックして、追加→新しい項目を選択。

ダイアロボックスで左側の項目からVisualC#アイテムを選択、

中央の項目からクラスを選択、名前をPlayer.csと入力して追加ボタンをクリックしてください。

これで 関連するものを収める入れ物(クラスの枠) の部分ができました。

つづいてクラスの中身を実装します。

クラスを作るにはclassキーワードに続けてクラス名を書き、ブロック内に クラスに関連する変数とメソッド を書きます。

クラス内で宣言する変数を メンバ変数 

クラス内で定義するメソッドを メンバメソッド といいます。

クラスの書式

class クラス名

メンバ変数の宣言

メンバメソッドの定義

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleRPG
{
    class Player
    {
        public string name; //プレイヤの名前
        public int hp; //プレイヤの体力

        //攻撃メソッド
        public void Attack()
        {
            Console.WriteLine(this.name + "は攻撃した");
        }

        //防御メソッド
        public void Defense()
        {
            Console.WriteLine(this.name + "は防御した");
        }
    }
}

 

メンバ変数(name、hp)を宣言し、

メンバメソッド(Attack、Defense)を定義しています。

このプログラムを実行すると警告がでますが、宣言した変数を初期化していないためです。あとで修正します。

・thisキーワード

name変数の前にthis.をつけています。

this 自分自身のインスタンスを表すキーワード で、this.変数名と書くことで、

 その変数が自分自身のインスタンスの変数=メンバ変数 であることを示します。

メンバ変数と同じ名前のローカル変数があっても、

thisをつけている方がメンバ変数、それ以外はローカル変数と区別できます。

02ショップクラスを作ってみよう

プレイヤクラスを作ったようにクラスを追加します。

名前はShop.csとします。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleRPG
{
    class Shop
    {
        public string shopName; //店名
        public int salesAmount; //売り上げ金額

        //販売メソッド
        public void Sell()
        {
            Console.WriteLine("お買い上げありがとうございます");
        }

        //買い取りメソッド
        public void Buy()
        {
            Console.WriteLine("お売りいただきありがとうございます");
        }
    }
}

 

メンバ変数にshopName、salesAmoount変数を宣言しています。

メンバメソッドにSell、Buyメソッドを定義しています。

03クラスのインスタンスを作ってみよう

クラスを作りましたが、 クラスも作っただけでは実行されません。 

 

Program.csタブを選択して、Mainメソッドに記述します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleRPG
{
    class Program
    {
        static void Main(string[] args)
        {
            //player1のインスタンスを作り、名前と体力を代入
            Player player1 = new Player();
            player1.name = "ほげ";
            player1.hp = 100;

            //player2のインスタンスを作り、名前と体力を代入
            Player player2 = new Player();
            player2.name = "ふが";
            player2.hp = 50;

            player1.Attack(); //player1が攻撃する
            player2.Defense(); //player2が防御する
        }
    }
}

インスタンス

クラスはプログラム中でintやstringなどのと同様に扱うことができます。

 Playerクラスをつくると、int型やstring型と同じようにPlayer型が使えるようになります。 

プレイヤクラスを使うため、プレイヤ型の変数を宣言する必要があります。

Player型player1変数を宣言しています。

 Player型の変数にはPlayerクラスの実体をいれます 

この実体のことをインスタンスといいます。

インスタンスの書式

クラス型の変数 = new クラス名();

 クラスはあくまでも型で、変数にはクラスを元に作成したインスタンスを代入します。 

 

先ほどのプログラムではインスタンスに名前と体力を代入しています。

インスタンスは作成元のクラスのメンバ(変数・メソッド)を持っています。

player1のインスタンスは元となるPlayerクラスの持つメンバ変数(name、hp)と、

メンバメソッド(Attack、Defence)を持っていて、それらを使うことができます。

メンバへのアクセス方法の書式

変数名.メンバ変数名

変数名.メンバメソッド名

以上で、クラスを作り、インスタンスを作って使うことができるようになりました。

04コンストラクタで初期値の代入忘れを防ごう

初期値の代入忘れを防ぐために、

 インスタンスを作ると同時にメンバ変数へ初期値を代入できるコンストラクタという仕組み があります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleRPG
{
    class Player
    {
        public string name; //プレイヤの名前
        public int hp; //プレイヤの体力

        public Player()
        {
            this.name = "ほげ";
            this.hp = 100;
        }

        //攻撃メソッド
        public void Attack()
        {
            Console.WriteLine(this.name + "は攻撃した");
        }

        //防御メソッド
        public void Defense()
        {
            Console.WriteLine(this.name + "は防御した");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleRPG
{
    class Program
    {
        static void Main(string[] args)
        {
            //player1のインスタンスを作り、名前と体力を代入
            Player player1 = new Player();

            Console.WriteLine(player1.name + "の体力は" + player1.hp);


        }
    }
}

コンストラクタ

Player.csに書かれているコードが、 インスタンス作成時に必ず呼び出される という特徴があります。

コンストラクタの名前はクラスと同じ名前にし、先頭にpublicをつけます。

コンストラクタの書式

public クラス名()

  クラスの初期化処理

Player player = new Player()←コンストラクタ;

 コンストラクタでメンバ変数に値を代入する処理を書いておけば、 必ずメンバ変数に初期値が入る というわけです。

ほげとふがが攻撃と防御をしたプログラムの時、

new Player();と書いていませんが実行できました。

理由は自分でコンストラクタを書いていない場合、

 コンパイラが自動で引数も処理もないコンストラクタを生成する からです。

これをデフォルトコンストラクタといいます。

自分でコンストラクタを書いた場合はデフォルトコンストラクタは生成されません。

05引数付きのコンストラクタを作ろう

引数付きのコンストラクタに修正しました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleRPG
{
    class Player
    {
        public string name; //プレイヤの名前
        public int hp; //プレイヤの体力

        public Player(string name, int hp)
        {
            this.name = name; //名前の初期値を代入
            this.hp = hp; //体力の初期値を代入
        }

        //攻撃メソッド
        public void Attack()
        {
            Console.WriteLine(this.name + "は攻撃した");
        }

        //防御メソッド
        public void Defense()
        {
            Console.WriteLine(this.name + "は防御した");
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleRPG
{
    class Program
    {
        static void Main(string[] args)
        {
            //player1のインスタンスを作り、名前と体力を代入
            Player player1 = new Player("ほげ",100);

            Console.WriteLine(player1.name + "の体力は" + player1.hp);


        }
    }
}

 

引数に名前と体力の初期値を渡しています。

初期値を忘れるとエラーが発生し、引数の渡し忘れを知らせてくれます。

 

usingとnamespae

プログラムのはじめに書かれているnamespace名前空間と呼びます。

namespaceを使うと自分の作ったプログラムに名前を付けることができます。

たとえば、大勢でゲームを作っていると、敵クラスひとつとっても、

「中村君が作った敵クラス」「菅原君が作った敵クラス」など

さまざまな敵クラスが作られます。namespaceを使うことで、

誰のクラスを使っているのかを明確にできます。

自分のnamespace以外のプログラムを使う場合は名前空間.クラス名という

書き方をします。

たとえば、中村君の作った敵クラスを使う場合は、

Nakamura.Enemyとかきます。

でもよく使うクラスを宣言するのにいちいち名前空間.クラス名と書くのは手間ですね。

よく使う名前空間についてはusing 名前空間;とプログラムの先頭に書いておくことで、

名前空間を書かずにクラス名だけで宣言できるようになります。

中村君の作った敵クラスを使うのであれば、using Nakamura;と書いておくことで、

Nakamura.Enemyではなく、単にEnemyと書けば中村君んのEnemyクラスが使われます。

 

Systemとライブラリ

何度も使ってきたコンソール上にメッセージを表示するConsole.WriteLineという命令は、

ConsoleクラスのWriteLineメソッドを実行するという意味になります。

ConsoleクラスはSystem名前空間に含まれています。

System名前空間はMicrosoft社があらかじめ準備してくれているもので、

アプリケーションの作成に必要となる基本的な機能のクラスがまとめられています。

このSystem名前空間はConsoleクラスを含め、非常によく使うため、

プログラムの先頭にusing System;とあらかじめ書かれています。

クラスなどをまとめて他人が利用できるようにしたものをライブラリと呼びます。

ライブラリはプログラムの先頭でusingをつけて名前空間を指定するか、

クラス名の前に名前空間をつけて呼び出すことで使用可能になります。

 

終わりに

オブジェクト指向、

クラスとインスタンスにきてしまいましたね。

あまり得意じゃないところです。

もともと、処理を分けずにガーと書いていく癖があるので、

まとめるということがちょっと苦手です。

ただ、言わんとしていることが何となくわかったので、

これも慣れが必要ですね。

オブジェクト指向難しい・・・

まぁ、似たような処理があれば分けると簡単に考えればいいのかな。

 

プログラミング初心者におすすめの本です。

この本は全カラーとなっていて、アルゴリズムを絵で分かりやすく表現しているところが初心者にはとても分かりやすいです。

アルゴリズムの基本からセキュリティのアルゴリズムまで載っていて

とても勉強になる本です。

プログラムを覚えるのと同時に大切な知識なので、

読んで損はないと思います。

超初心者がおすすめできる本です。

 

それではまた次回。

 

 

 

シェアしてくれたら嬉しいです!!

コメントを残す

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