使用している言語に関係なく、最初にデザインから始めることをお勧めします。メニュー項目のセットが異なるユーザー タイプ (「ゲスト」など) をもう 1 つ追加する必要があるとします。その場合、何をする必要がありますか?もう1つ「if」ステートメントを追加し、基本的にコピーペーストします。これはまったく良くありません。では、10 種類のユーザーがいるとどうなるか想像してみてください。あなたの switch-case ステートメントは巨大な怪物になり、あなたのチームの誰もが (あなたでさえも) そこに新しいアイテムを追加したり、既存のものを変更したりすることを恐れるでしょう.
わかりました、それは悲しかったです、今は楽しみましょう:)
理想的には、Page_Load メソッドに配置する予定の「クライアント」コードは 1 行だけにする必要があります。
protected void Page_Load(object sender, EventArgs e){
BuildMenu();
}
メソッドに 1 行しかなく、すべてが「魔法のように」整理されているとは、なんとすばらしいことでしょう。
ユーザータイプが利用できるアイテムを規制するある種のポリシーがあるとしましょう。基本的なインターフェースはとてもシンプルです:
public abstract class MenuItemsPolicy{
public abstract List<MenuItem> GetMenuItems();
protected virtual MenuItem CreateMenuItem(string text, string url){
//add parameter checks, etc.
MenuItem item = new MenuItem();
item.Text = text;
item.NavigateUrl = url;
return item;
}
}
現時点では、2 つのユーザー タイプがあるため、正確に 2 つの実装があります。依頼者:
public class RequestorMenuItems : MenuItemsPolicy{
public override List<MenuItem> GetMenuItems(){
return new List<MenuItem>(){
CreateMenuItem("Request A New Course", "~/Courses/RequestNewCourse.aspx"),
CreateMenuItem("View My New Course Requests", "~/Courses/ViewMyCourseRquests.aspx")
};
}
}
そして管理者(「マージ」がどこにあるかに注意してください)
public class AdministratorMenuItems : MenuItemsPolicy{
public override List<MenuItem> GetMenuItems(){
List<MenuItem> resultingMenuItems = (new RequestorMenuItems()).GetMenuItems();
resultingMenuItems.Add(CreateMenuItem("View Un-Approved Requests", "~/Administration/ViewUnAprroved.aspx"));
return resultingMenuItems;
}
}
ご覧のとおり、リクエスターのアイテムを取得し、そこにもう 1 つのアイテムを追加します。これを将来変更する必要がある場合、抽象エンティティに依存しているため、クライアント/呼び出し元のコードは実装の詳細について何も知りません。つまり、クライアント/呼び出しコードを変更する必要はなく、ルールが変更されます。または、特定のユーザー タイプで利用可能なリンクを将来変更する必要がある場合。
例を単純化するために、ユーザー タイプに enum を使用しました。
public enum UserAccessType{
Requestor = 0,
Administrator = 1
}
それでは、実装を見てみましょう。シンプルで標準的な asp.net メニュー コントロールをページに配置しました。
<form id="form1" runat="server">
<asp:menu runat="server" Id="mainMenu"></asp:menu>
<div>
そして、ここに「コードビハインド」があります:
public partial class _Default : System.Web.UI.Page{
//We will initialize this variable a bit later
//for example from URL parameter ?userType=1 or something like that
private UserAccessType _currentUserAccess;
//Ideally, dictionary should be a member of a class
//I left a simple dictionary just to avoid over-complicaation
private readonly Dictionary<UserAccessType, MenuItemsPolicy> _userMenuItems = new Dictionary<UserAccessType, MenuItemsPolicy>();
protected override void OnInit(EventArgs e){
//Associating our user types with Menu Items
_userMenuItems.Add(UserAccessType.Administrator, new AdministratorMenuItems());
_userMenuItems.Add(UserAccessType.Requestor, new RequestorMenuItems());
//Init the Current User / Access Type. For example, you can read the value from Request["UserType"]
//Here I've just assigned a value
_currentUserAccess = UserAccessType.Administrator;
base.OnInit(e);
}
protected void Page_Load(object sender, EventArgs e){
BuildMenu();
}
private void BuildMenu(){
mainMenu.Items.Clear();
var menuItems = GetMenuItems();
foreach(var item in menuItems){
mainMenu.Items.Add(item);
}
}
private List<MenuItem> GetMenuItems(){
MenuItemsPolicy currentPolicy = _userMenuItems[_currentUserAccess];
return currentPolicy.GetMenuItems();
}
}
上記の例があなたの質問に答えてくれることを願っています。もちろん、この例は理想的ではありません。ただし、コードを比較的クリーンで保守しやすい状態に保つのに役立ちます。
PS 記事を読むことをお勧めします:
http://objectmentor.com/resources/articles/Principles_and_Patterns.pdf
OCP の例を参照してください。状況にどれだけ近いかがわかります。
読んでくれてありがとう :)