1

Visual Studio 2010 を使用して C# を初めて使用します。私の古い PHP では、このメニューを作成するために、ハイパーリンクの 2 つの配列を作成します。「要求者」がログインすると Level1 配列が表示され、「管理者」がログインすると Level1 AND Level2 配列がマージされ、並べ替えられて表示されます。C# では、デフォルト ページ (Site.Master ページがある) で、自分がこれをしていることに気づきます:

case NewCourseRequestView.Administrator:
    if (access.Administrator)
    {
        UserTypeLabel.Text = "Administrator Details:";

        AdministratorMenuList.Items.Add("View Un-Approved Requests");
        adminContent.Visible = true;
    }
    break;

case NewCourseRequestView.Requestor:
    if (access.Requestor)
    {
        UserTypeLabel.Text = "Requester Details:";

        RequestorMenuList.Items.Add("Request A New Course");
        RequestorMenuList.Items.Add("View My New Course Requests");
        requestContent.Visible = true;
    }
    break;

どうやって

  1. これらのリスト項目をハイパーリンクとして機能させる AND
  2. これらの 2 つのリストを 2 つの別々の配列 (コレクション?) に入れ、アクセス権がある場合はそれらをマージします。管理者?

かなり具体的な説明が必要です、ありがとう!

4

2 に答える 2

1

使用している言語に関係なく、最初にデザインから始めることをお勧めします。メニュー項目のセットが異なるユーザー タイプ (「ゲスト」など) をもう 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 の例を参照してください。状況にどれだけ近いかがわかります。

読んでくれてありがとう :)

于 2012-04-16T23:34:00.737 に答える
1

最初に提案することは、コレクションのタイプとしてオブジェクトが必要であることです。これらのオブジェクトには、URL と Text プロパティがあります。

class UrlText : IEquatable<UrlText>
{
    public string Url { get; set; }
    public string Text { get; set; }

    public UrlText(string url, string text)
    {
        this.Url = url;
        this.Text = text;
    }

    #region IEquatable<UrlText> Members

    public bool Equals(UrlText other)
    {
        return this.Url.Equals(other.Url);
    }

    #endregion
}

わずかな変更を加えて、記述したとおりにコードを続行します。

string baseUrl = "http://localhost/myapp";

case NewCourseRequestView.Administrator:
    if (access.Administrator)
    {
        UserTypeLabel.Text = "Administrator Details:";

        AdministratorMenuList.Items.Add(new UrlText(baseUrl + "/viewunapproved.aspx", "View Un-Approved Requests"));
        adminContent.Visible = true;
    }
    break;

case NewCourseRequestView.Requestor:
    if (access.Requestor)
    {
        UserTypeLabel.Text = "Requester Details:";

        RequestorMenuList.Items.Add(new UrlText(baseUrl + "/RequestCourse.aspx","Request A New Course"));
        RequestorMenuList.Items.Add(new UrlText(baseUrl + "/viewNewRequest.aspx","View My New Course Requests"));
        requestContent.Visible = true;
    }
    break;

最後に、コレクションをマージしたいときはいつでも、次のような簡単なことを行います:

public static List<UrlText> MergeLists(List<UrlText> listAdmin, List<UrlText> listUser)
{
    List<UrlText> result = new List<UrlText>();
    foreach (UrlText myMenuItem in listAdmin)
    {
        result.Add(myMenuItem);
    }

    foreach (UrlText myMenuItem in listUser)
    {
        if (!result.Contains(myMenuItem))
            result.Add(myMenuItem);
    }

    return result;
}

そしてそれを使用します(インターフェイスから実装された equals メソッドにより、リストの Contains メソッドを正しく使用できます):

mergedList = MergeLists(AdministratorMenuList, RequestorMenuList);
于 2012-04-16T23:15:28.087 に答える