C#でオブジェクト指向をするために必要な知識や手法について、このブログではよく解説を行っています。「【C#】クラスを使ってカプセル化をする方法」では、オブジェクト指向の概要からクラスを使ってカプセル化を実行する方法などを紹介してきました。
今回、この記事ではカプセル化をするにあたって必要となる「プロパティ」を解説します。プロパティはクラス内外で値をやり取りするために使われる機能になります。プロパティを介することで、値の公開範囲を決定し、不要な情報・設定して欲しくない情報をクラスで設定できるようになります。
プロパティとは
プロパティは一般的にgetterやsetterと呼ばれる機能で、クラスの外側から値を設定したりクラスの外側から値を取得したりするために使われる記述方法になります。クラス内部にpublicで定義した変数を公開すると、直接的に値の書き換えが可能となってしまうため、「門」のような役割をしてくれるプロパティを介するほうが一般的になっています。
基本的なプロパティの書き方
まずはC#におけるプロパティの書き方を簡単に紹介します。プロパティについては「【C#】プロパティとは | プロパティとフィールドを使う方法」で解説しているので、理解がまだな人はコチラからチェックして見てください。C#でプロパティを記述する方法は以下のようになります。
//基本的なプロパティ①
public class Product1
{
public int Id { get; set; }
public string Name { get; set; }
}
//基本的なプロパティ②
public class Product2
{
public int Id
{
get { return _id; }
set { _id = value; }
}
int _id;
public string Name
{
get { return _name; }
set { _name = value; }
}
string _name;
}
もともとは②で記述する方法が基本で、筆者もIT企業での新人研修ではそちらの方法を紹介していました。しかしながら、最近では①で記述するほうが多いように感じています。というわけで、基本的には①での記載を覚えておけばよいと思います。②のように内部変数と分けて定義する記述方法は、WPFなどフロントに近い機能を作成するときに使用するときに多いです。
getとsetの区別が曖昧になってしまうことがありますが、そういう時は「クラスの外から」と考えると覚えやすいですね。「クラスの外からgetする」「クラスの外からsetする」と覚えるとgetterとsetterの機能が分かりやすくなります。プロパティはあくまでも「外からの要求に対する門番」だと思えば良いのです。
オブジェクト指向的なプロパティの書き方
ここまでは一般的なプロパティについて紹介してきました。もう少しオブジェクト指向で使用されるプロパティについて解説したいと思います。オブジェクト指向では主に「外部への公開」と「設定範囲の限定」をすることが重要です。
外部への公開で言えばそれはpublicとして公開していいいか、privateとして公開しないべきなのか。「設定範囲の限定」で考えると「setter」のアクセス修飾子はpublicかprivateかといったことを考えるわけです(ここではinternalやprotectedは考えません)。となるとオブジェクト指向で使われるのは「外部には公開するけど、外側から設定させない」という以下の用法になります。
//オブジェクト指向的なプロパティ
public class Product3
{
public int Id { get; private set; }
public string Name { get; private set; }
}
上記のように記述することで、クラスの外側から値を設定することは不可能であり、あくまでもクラスの内側からでしか値を設定することはできないプロパティの状態にすることが可能になります。オブジェクト指向で重要なことは、外側からの操作は「できる限り隠す」そして「可能な限り操作させない」になりますので、基本形は上記であると割り切ってよいでしょう。
ただし明示的にクラスの外側から値を受け取りたい・受け取っても良いプロパティの場合は、単純に「set」と記述して外側からの設定を許すようにします。そういう場合は外側から値を受け取ることを前提に処理をさせる必要があるので、プロパティの設定値のチェック(例えばnullチェック)などはしっかりとするようにしましょう。
プロパティで「操作可能範囲」を指定する
プロパティの書き方やアクセス修飾子の設定方法によって、値の操作可能範囲を他の実装者に明示的に伝えることができます。publicが付与されているプロパティであればクラスの外側に対する要素です。しかしながら、getterとsetterのアクセス修飾子をさらに指定することで、クラスの外側から設定することができるのか、クラスの内側からの設定しか受け付けないのかを決められます。
近年ではgetter(クラスの外からgetすることが可能)は単に「set;」と記載して参照できるようにし、setter(クラスの外側からsetすることが可能)は「private set;」もしくは「記述しない(この場合はsetのみ)」が多いような気がしています。オブジェクトの中身が勝手に外側から変更されるのを防ぐには、実装者の意図をプロパティを通して伝えるようにしましょう。
オブジェクト指向では「公開範囲」や「操作可能範囲」が重要なテーマとなっているため、それを体現するためにも「意図を持ったプロパティ設定」が重要となります。この記事をしっかりと理解してプロパティを正しく設定できるようになってもらえれば嬉しいです。