アクセシビリティによる実装の隠蔽
オブジェクト指向においては、ユーザーはオブジェクトの内部実装を隠蔽し、外部に公開する必要のある操作や属性のみを公開させます。また、C#においてはプロジェクト外へのクラスの隠蔽も可能です。この公開範囲を制限する方法がアクセシビリティ
というものです。
アクセシビリティ | 参照可能な範囲 |
---|---|
public | プロジェクト外からもアクセス可能 |
internal | 同一プロジェクト内のみアクセス可能 |
protected | 派生クラスのみアクセス可能 |
private | クラスの内部のみアクセス可能 |
アクセシビリティの原則
コードの品質を安定させ、設計変更による影響を局所化するために可能な限りアクセシビリティは制限が強くなるようにして下さい。
- クラスは可能な限りinternalにしてpublicなクラスを減らして下さい。
- メソッドはクラスの内部実装上必要で外からアクセスしないものはprivate、継承クラスからアクセスさせたいメソッドはprotectedにします。
- クラスの変数はprivateとして、プロパティを定義します。
- プロパティも変更の必要がない場合はsetterが無いようにします。
メソッドの隠蔽例
以下のようなサービスクラスを作成したとします。
共通処理であるCreateModels()
はこのクラ ス内からしか呼び出す必要がないので、アクセシビリティを private にして隠蔽します。
メソッドを隠蔽する例
using System.Collections.Generic;
using NextDesign.Core;
namespace MyExtension.Core
{
/// <summary>
/// ユースケースモデルを作成します
/// </summary>
public class UseCaseModelCreationService
{
/// <summary>
/// アクターを作成します
/// </summary>
/// <param name="owner">作成したアクターを所有するモデル</param>
/// <param name="names">作成したアクターのNameに設定する文字列</param>
/// <returns>作成したアクター</returns>
public IEnumerable<IModel> CreateActors(IModel owner, IEnumerable<string> names)
{
var createdModels = CreateModels(owner, "Actors", "Actor", names);
return createdModels;
}
/// <summary>
/// ユースケースを作成します
/// </summary>
/// <param name="owner">作成したユースケースを所有するモデル</param>
/// <param name="names">作成したユースケースのNameに設定する文字列</param>
/// <returns>作成したーユースケース</returns>
public IEnumerable<IModel> CreateUseCases(IModel owner, IEnumerable<string> names)
{
var createdModels = CreateModels(owner, "UseCases", "UseCase", names);
return createdModels;
}
// 次のメソッドは外部から直接呼び出さないので非公開にします
/// <summary>
/// モデルを作成します
/// </summary>
/// <param name="owner">作成モデルを所有するモデル</param>
/// <param name="fieldName">作成モデルを所有するフィールド名</param>
/// <param name="className">作成するモデルのメタクラス名</param>
/// <param name="names">作成したモデルのNameに設定する文字列</param>
/// <returns>作成したモデル</returns>
private IEnumerable<IModel> CreateModels(IModel owner, string fieldName, string className, IEnumerable<string> names)
{
var createdModels = new List<IModel>();
foreach (var name in names)
{
var model = owner.AddNewModel(fieldName, className);
model.SetField("Name", name);
createdModels.Add(model);
}
return createdModels;
}
}
}
クラスの隠蔽例
ロジックをクラスにまとめて共通化した例です。
ModelCreationService
クラスはプロジェクト内からしか利用しないため、アクセシビリティを internal にします。
クラスを隠蔽する例
using System.Collections.Generic;
using NextDesign.Core;
namespace MyExtension.Core
{
/// <summary>
/// ユースケースモデルを作成します
/// </summary>
public class UseCaseModelCreationService
{
/// <summary>
/// アクターを作成します
/// </summary>
/// <param name="owner">作成したアクターを所有するモデル</param>
/// <param name="names">作成したアクターのNameに設定する文字列</param>
/// <returns>作成したアクター</returns>
public IEnumerable<IModel> CreateActors(IModel owner, IEnumerable<string> names)
{
var modelCreationService = new ModelCreationService();
var createdModels = modelCreationService.CreateModels(owner, "Actors", "Actor", names);
return createdModels;
}
/// <summary>
/// ユースケースを作成します
/// </summary>
/// <param name="owner">作成したユースケースを所有するモデル</param>
/// <param name="names">作成したユースケースのNameに設定する文字列</param>
/// <returns>作成したーユースケース</returns>
public IEnumerable<IModel> CreateUseCases(IModel owner, IEnumerable<string> names)
{
var modelCreationService = new ModelCreationService();
var createdModels = modelCreationService.CreateModels(owner, "UseCases", "UseCase", names);
return createdModels;
}
}
// 次のクラスはプロジェクト外に公開しません
/// <summary>
/// モデルを作成します
/// </summary>
internal class ModelCreationService
{
/// <summary>
/// モデルを作成します
/// </summary>
/// <param name="owner">作成モデルを所有するモデル</param>
/// <param name="fieldName">作成モデルを所有するフィールド名</param>
/// <param name="className">作成するモデルのメタクラス名</param>
/// <param name="names">作成したモデルのNameに設定する文字列</param>
/// <returns>作成したモデル</returns>
public IEnumerable<IModel> CreateModels(IModel owner, string fieldName, string className, IEnumerable<string> names)
{
var createdModels = new List<IModel>();
foreach (var name in names)
{
var model = owner.AddNewModel(fieldName, className);
model.SetField("Name", name);
createdModels.Add(model);
}
return createdModels;
}
}
}
インタフェースによる実装の隠蔽
インタフェースによる実装の隠蔽を徹底することで、ドメイン層のクラス実装は原則internal化できるはずです。これにより設計変更に非常に強いアーキテクチャを実現できます。 詳細は インタフェースによる実装の隠蔽 を参照してください。