C#初心者によるC#のお勉強やろう12 カプセル化編

病気全然治ってないみたいです。なんということだ。el(える)です。

 

今回はカプセル化の勉強です。

カプセル化なんて聞いただけでは何のことだかさっぱりです。

カプセル化はなぜ必要

これまで作ってきたクラスのメンバ変数やメンバメソッドの前には、

publicというキーワードをつけてきました。

このpublicはアクセス修飾子と呼ばれるものです。

アクセス修飾子がpublicであれば、

 他のクラスから変数名.メンバ名と書いてメンバ変数やメンバメソッドにアクセスできます。 

 

一方、アクセス修飾子にはpublicとは逆の機能を持つprivateもあります。

privateにすると 外部からはメンバにアクセスできなくなります。 

アクセス修飾子を使うことによって、 他のクラスからメンバにアクセスできるかどうかを決める ことが出来ます。

特に、メンバ変数やメンバメソッドをprivateにしてアクセスさせないようにすることをカプセル化といいます。

なぜ他のクラスからアクセスを制限する必要があるのでしょうか。

2つの理由があります。

  • クラスの中で、利用してほしい機能だけを使えるようにする。
  • クラスを使う人がメンバ変数におかしな値を入れないようにする

必要な機能だけを使えるようにする

クラスで内部的に使っているメンバのすべてを知る必要はありません。

全部見えてしまうとどれを使えばよいか分かりにくくなってしまいます。

そこでアクセス修飾子をつかって、 見る必要のないものは隠し、使わせたいメンバだけにアクセスできるようにします。 

おかしな値を入れられないようにする

クラスのメンバ変数には外部から直接アクセスできないようにしておき、

 メンバ変数に意図しない値が入ることを防ぎます。 

01アクセス修飾子でメンバ変数に鍵をかけよう

 Playerクラスのメンバ変数(nameとhp)へのアクセスを不可能にして、メンバメソッドだけにアクセスできるようにしたものです。 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleRPG
{
    class Player
    {
        private string name; //プレイヤの名前
        private 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)
        {
            Player player = new Player("ほげ", 35);
            player.Attack(); //publicなメソッドなので呼び出せる

        }
    }
}

アクセス修飾子

アクセス修飾子

アクセス修飾子は、 メンバ変数やメンバメソッドを○○.変数名、○○.メソッド名と書いて呼び出せるようにするかどうかを指定できます。 

アクセス修飾子 意味
public 全てのクラスからアクセス可能
protected 自分のクラスまたは派生クラスからのみアクセス可能
private 自分のクラス以外からはアクセス不可能
 publicで宣言した変数はどのクラスからでもアクセスできます。   privateで宣言した変数は自分のクラス以外からはアクセスできません。 

protectedは継承で勉強します。

アクセス修飾子の書式

アクセス修飾子 型名 メンバ変数名;

アクセス修飾子 戻り値の型 メンバメソッド名(){};

アクセス修飾子をつけないで宣言すると、privateをつけて宣言したものとみなされます。

02メンバ変数にアクセスできる手段を作ろう

プレイヤの名前(name)は一度コンストラクタで代入したら書き換えることはありませんが、

体力(hp)はダメージを受けたり回復したりと後から書き換える可能性があります。

正しい値と判定した時だけhp変数に値を代入できるようにしましょう。

メンバ変数に値を代入・取得するメンバメソッドを追加しています。

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

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

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

        //hp変数に値を代入する
        public void SetHp(int hp)
        {
            this.hp = hp;
            if(this.hp < 0)
            {
                this.hp = 0;
            }
        }

        //hp変数の値を取得する
        public int GetHp()
        {
            return this.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)
        {
            
            Player player = new Player("ほげ", 500);
            //プレイヤの体力を2000減らしてnewHP変数に代入する
            int newHP = player.GetHp() - 2000;
            //newHPをプレイヤの体力に代入する
            player.SetHp(newHP);
            //プレイヤの今の体力を表示する
            Console.WriteLine(player.GetHp());

        }
    }
}

アクセス修飾子

hp変数に値を代入するSetHpメソッドと、

hp変数の値を取得するGetHpメソッドを追加しています。

 メンバ変数にアクセスするためのメソッドをアクセサといいます。 

SetHpメソッドは引数にhpを受け取り、メンバ変数hpに代入します。

hp変数がおかしな値にならないようにif文でチェックして、

hp変数がマイナスの時は0を代入し直しています

このように、 publicなアクセサを介してprivateなメンバ変数へアクセスする仕組み はよく使うので覚えておきましょう。

GetHpメソッドはhpメンバ変数の値を返します。

これらのアクセサは publicにして外部のクラスからアクセス可能 にしています。

03プロパティで簡潔にまとめる

アクセサを使うと冗長的な書き方となってしまいます。

このような書き方を避けるためにC#にはプロパティという仕組みがあります。

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

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

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

        //Hpプロパティ
        public int Hp
        {
            set
            {
                this.hp = value;
                if(this.hp < 0)
                {
                    this.hp = 0;
                }
            }
            get
            {
                return this.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)
        {
            
            Player player = new Player("ほげ", 500);
            //playerのHpプロパティに代入
            player.Hp -= 2000;
            Console.WriteLine(player.Hp);

        }
    }
}

プロパティ

プロパティとはメンバ変数のように使えるアクセサを作る仕組みです。

 他のクラスからプロパティを使う時はメンバ変数にアクセスする感覚で使えます。 

内容としては、Hpという名前のプロパティを作っています。

プロパティ名は基本的に大文字で始めます

Setブロックには メンバ変数に値を代入するときの処理 を書き、

メンバ変数に代入する値は、プロパティ内ではvalue変数に保持されます。

value変数の値をhpメンバ変数に代入して、hpメンバ変数がマイナスの時は、

0を代入し直しています。

getブロックの中には メンバ変数の値を取得するときの処理 を書きます。

hpメンバ変数の値をreturn文で返しています。

プロパティの書式

    public プロパティの型名 プロパティ名
    {
        set
        {
            変数名 = value;
        }
        get
        {
            return 変数名;
        }
    }

 

プロパティは メンバ変数に直接アクセスするかのように扱う ことが出来ます。

 

staticキーワード

Mainメソッドが呼び出すメソッドにはstaticをつけて定義してきましたが、

自分で作ったクラスのメンバには付けてきませんでした。

メンバ変数やメンバメソッドの前にはstaticキーワードをつけることができます。

staticをつけたメンバは、インスタンスではなくクラス自体に属するようになり、

 インスタンス間で共有される値 になります。

class test
    {
        public static int money;

        public static string GetTeamName()
        {
            return "Team C#";
        }
    }

メンバ変数とメンバメソッドにstaticをつけて宣言した例です。

staticをつけたメンバは静的メンバとよばれます。

静的メンバはクラス自体に属する値なので、使用する場合にはtest.moneyとして、

クラス名.メンバ変数で値を代入・取得できます。

またGetTeamNameメソッドはstaticが付いているので、

こちらもtestクラスに属するメソッドになります。

クラスに属しているためtest.GetTeamName()のように、

クラス名.メソッド名で呼び出すことができます。

これまでも、WriteLineメソッドはConsole.WriteLineと書いてきましたね。

このような使い方ができるのはstaticを利用して作られているためです。

staticをつけたメソッドから、staticの付いていないメソッドを呼び出すことはできません。

オーバーロード

メソッドを定義するとき、引数の個数や引数の型が異なっていれば、

 同じ名前のメソッドを複数定義する ことができます。

これをメソッドのオーバーロードと呼びます。

これまで使用してきたConsole.WriteLineメソッドは引に数値を与えた場合も、

文字列を与えた場合も正しく動作しました。

Consoleクラス内でWriteLineメソッドが何種類もオーバーロードされているからです。

    public static void WriteLine(int value)
    {
        //数値を表示する処理;
    }

    public static void WriteLine(string value)
    {
        //文字列を表示する処理;
    }

 

コントラスタもオーバーロードすることができます。

引数なしのコントラスタとint型の引数を取るコントラクタの2種類を作ったとします。

インスタンスを引数なしで作った場合は、引数なしのコンストラクタが実行され、

int型の引数を渡してインスタンスを作った場合はint型の引数をもつインスタンスが実行されます。

class test
    {
        int hp;

        public test()
        {
            this.hp = 100;
        }

        public test(int hp)
        {
            this.hp = hp;
        }

    static void Main()
        {
            test test1 = new test();    //HPは100
            test test2 = new test(500); //HPは500
        }
        
    }

 

終わりに

ん~難しいですね。

言わんとしていることは分かるのだけど、なんかモヤっとしてるというか。。。

何度も読んでると頭に入ってくるのかなぁ。

まぁ家にはいろいろなC#の入門書があるから読んでたらどうにかなるか。

どうにかなる精神でいきましょう。

 

 

初心者におすすめのC#の入門書です。

僕が分かりやすいと思った入門書となります。

Unityの本は基礎の基礎なので、2冊読んだ方が知識として身につきます。

これからC#をはじめる人にはおすすめの2冊です。

 

 

それではまた次回。

 

 

 

刀剣好きのメルマガ




 

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

コメントを残す

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