オブジェクト指向
-カプセル化-

■カプセル化

カプセル化とはオブジェクト指向によるプログラミングを行うための概念の1つです。

●カプセル化の目的
	カプセル化の目的はクラスが持つ情報や機能の公開に制限をかけることです。
	クラスでは数多くの情報や機能を有しますが、その全てを利用者に公開する必要はありません。
	利用者が使用すると思われる情報や機能だけを開示するだけで問題ありません。
	むしろ、全ての情報を公開したほうが利用者が間違った操作をする可能性が高まり、
	問題が発生する可能性も高まります。
	これはプログラムでも、現実の世界でもいえることです。

	現実の例:
		テレビ
			利用者に与えられている機能
				電源ON	=> テレビをつける
				電源OFF	=> テレビを消す
				チャンネルを変える => 番組を変える
				音量ボタン => 音量を変更する
					
			利用者に与えられている情報
				名称 => REGZA等
				製造番号 => xxxx-xxxxx
				サイズ => 何インチか
				HDMI端子 => 対応 or 非対応
				USB => 対応 or 非対応

		上の例でテレビに対して公開されている機能と情報の一例を書き出しています。
		利用者はこの機能や情報だけを知っていれば、問題なく使用できます。
		わざわざ内部の配線やチャンネル切り替えの内部仕様について知る必要はありません。
		それらが公開されていた場合、好奇心旺盛な利用者が改変する可能性すらあり、
		それでテレビが壊れたとしても、「説明書に書いてあったことを試しただけ」と
		いわれたら提供側の問題として扱われます。
		説明書に載っていないからこそ「勝手に改変するのが悪い」と言い切れます。

	プログラムの例:
		従業員クラス
			/*
				従業員クラス
					メンバ変数のm_Salaryで給与の支払い額を設定しているので、
					絶対にいじらないこと!!!!
			*/
			class Jugyoin
			{
			public:
				Jugyoin()
				{
					m_Salary = 200000;
				}

				int m_Salary;	// 給料

				void ShowSalary(void)
				{
					printf("給与は%d円です\n", m_Salary);
				}
			};

			/*
				給与支払いシステムクラス
				通称:社長クラス
			*/
			class SalaryManager
			{
			public:
				void SalaryPayment(int salary)
				{
					printf("給与を%d円支払いました。\n", salary);
				}
			};

			void main(void)
			{
				SalaryManager syattyosan; // 社長

				Jugyoin satou;	// 佐藤
				Jugyoin suzuki;	// 鈴木

				satou.ShowSalary();
				suzuki.ShowSalary();

				syattyosan.SalaryPayment(satou.m_Salary);
				// 今月がんばったからこれくらいいいよね!! by 鈴木
				suzuki.m_Salary = 2000000; 
				syattyosan.SalaryPayment(suzuki.m_Salary);
			}

		上の例では従業員クラスを作成し、コンストラクタで従業員の給与を決めています。
		satou、suzukiともに200000円が給与として設定されていますが、
		suzukiは給与が不満なのか勝手に給与を10倍に設定しています。
		悪いのは勝手にコードを改変したsuzukiですが、suzukiは言い訳として
		「魔が差しました。でも、自分の給与がこんなに簡単に改変できるのが悪い!!」と
		いってくるかもしれません。
		こんな言い訳を言わせないように給与の設定を簡単に変更できないようにして、
		魔が差すことがないようにする必要があります。
		その状態で変更を行ったら、「簡単に変えられない現状でも変更を行ったんだから
		魔が差すとかはない。おまえが100%悪い!!!」と言い切れます。

	このように現実世界でも、プログラムの世界でも情報を100%開示する必要はなく、
	100%開示したからこそ問題が発生する可能性があります。
	カプセル化は公開する情報、機能を制限することで、問題の発生を最小限にとどめます。


●制限のかけかた
	クラスの情報や機能に制限をかけるにはクラスの持つメンバに対してアクセス指定子を使用します。
	アクセス指定子には「public」「private」「protected」があります。
	※アクセス指定子についてはアクセス制御に書いていますが、
	簡単に説明すると以下の通りです。

		・public
			どのクラスからでも使用することができる

		・private
			クラス内でのみ使用することができる

		・protected
			クラス内と継承先のクラスで使用することができる

		制限をかけるには「private」か「protected」を使用します。

	・制限をかけたコード
		/*
			従業員クラス
				メンバ変数のm_Salaryで給与の支払い額を設定しているので、
				絶対にいじらないこと!!!!
		*/
		class Jugyoin
		{
		public:
			Jugyoin()
			{
				m_Salary = 200000;
			}

			void ShowSalary(void)
			{
				printf("給与は%d円です\n", m_Salary);
			}

		private:
			// これで勝手に変更できまい!!! by 社長
			int m_Salary;	// 給料
		};

		/*
			給与支払いシステムクラス
			通称:社長クラス
		*/
		class SalaryManager
		{
		public:
			void SalaryPayment(int salary)
			{
				printf("給与を%d円支払いました。\n", salary);
			}
		};

		void main(void)
		{
			SalaryManager syattyosan; // 社長

			Jugyoin satou;	// 佐藤
			Jugyoin suzuki;	// 鈴木

			satou.ShowSalary();
			suzuki.ShowSalary();

			syattyosan.SalaryPayment(satou.m_Salary);	// エラー①
			// 今月がんばったからこれくらいいいよね!! by 鈴木
			suzuki.m_Salary = 2000000; 			// エラー②
			syattyosan.SalaryPayment(suzuki.m_Salary);	// エラー③
		}

	最初のコードの「Jugyoin」クラスのメンバ変数「m_Salary」のアクセス指定子を
	「public」から「private」に変更しました。
	これによって、main関数の最後の3行がエラーとして扱われます。
	「private」にしたことで「m_Salary」をクラスの外でアクセスする権限がなくなったからです。

●間接的なアクセス
	「public」から「private」に変えたことで「m_Salary」を簡単に変更できなくなりましたが、
	今度はSalaryPayment関数の引数で使用している「m_Salary」の使用も不可能になりました。
	この問題を解決するためにアクセサと呼ばれる方法を使用します。

	・アクセサ
		アクセサとは「getter(ゲッター)」と「setter(セッター)」があり、
		間接的に制限がかかったメンバ変数に対してアクセスできるメンバ関数のことです。

		getter:
			アクセス制限がかかっている変数の取得

			書式:
				メンバ変数のデータ型 Get***(void)
				{
					return メンバ変数;
				}

				※***はメンバ変数の名前

			具体例:
				int GetSalary()
				{
					return m_Salary;
				}

		setter:
			アクセス制限がかかっている変数の変更

			書式:
				void Set***(メンバ変数のデータ型)
				{
					return メンバ変数;
				}

				※***はメンバ変数の名前

			具体例:
				void SetSalary(int salary)
				{
					m_Salary = salary;
				}

	・アクセサの注意点
		アクセサを使用することでメンバ変数の間接的な取得、変更が可能となりますが、
		全てのメンバ変数に対してアクセサの設定を行ってはいけません。
		アクセサは「クラスの外でメンバの情報が必要な時」か、
		「クラスの外からメンバの変更が必要な時」に使用する関数なので、
		全てのメンバ変数にアクセサをつけたら「public」とほとんど変わりません。
		以下にJugyoinクラスのm_Salaryに対してアクセサを設定したコードを記述しますが、
		setterは使用せず、getterのみ使用しています。
		理由は現状m_Salaryはクラスの外での変更の必要はなく値の取得だけでいいからです。

		コード例:
			/*
				従業員クラス
					メンバ変数のm_Salaryで給与の支払い額を設定しているので、
					絶対にいじらないこと!!!!
			*/
			class Jugyoin
			{
			public:
				Jugyoin()
				{
					m_Salary = 200000;
				}

				void ShowSalary(void)
				{
					printf("給与は%d円です\n", m_Salary);
				}

				// 給与の確認したい時に使う by 社長
				int GetSalary()
				{
					return m_Salary;
				}

			private:
				// これで勝手に変更できまい!!! by 社長
				int m_Salary;	// 給料
			};

			/*
				給与支払いシステムクラス
				通称:社長クラス
			*/
			class SalaryManager
			{
			public:
				void SalaryPayment(int salary)
				{
					printf("給与を%d円支払いました。\n", salary);
				}
			};

			void main(void)
			{
				SalaryManager syattyosan; // 社長

				Jugyoin satou;	// 佐藤
				Jugyoin suzuki;	// 鈴木

				satou.ShowSalary();
				suzuki.ShowSalary();

				syattyosan.SalaryPayment(satou.GetSalary());
				// 今月がんばったからこれくらいいいよね!! by 鈴木
			//	suzuki.m_Salary = 2000000; 			// エラー②
				syattyosan.SalaryPayment(suzuki.GetSalary());
			}

	これで先ほど発生していたエラーの①と③がなくなり、m_Salaryも改変されることなく
	無事給与を支払うことができます。

●メリット
	・アクセス制限によりクラスの誤動作を最小限にとどめる
		クラスが持つメンバに対してアクセス制限をかけて、
		必要最低限のメンバだけアクセスできるようにすることにより、
		利用者が誤ったクラスの使い方をすることを最小限にとどめます。
		これよって開発側が予期しないバグの発生率が大幅に下がります。

	・クラス間のつながりを浅くする
		クラスが開示しているメンバの数が少ないということは
		それだけ、他のクラスとのつながりが浅くなりやすいことを意味します。
		例えば100あるメンバの全てがpublicだった場合、その100のメンバ全てが
		どこかのクラスとつながる可能性があります。
		ですが、100のメンバのうち10だけがpublicなら10のメンバだけが、
		他のクラスとつながる可能性があり、他の90のメンバがつながることはありません。

OOPの理想である独立性の高いクラスを作成するためにはカプセル化を使用することは必須です。