3

私は新しいプロジェクトに取り組んでおり、適切な設計方法を遵守しようとしています。switch ステートメントで問題が発生しましたが、問題があることはわかっていますが、オブジェクト指向の方法でそれをリファクタリングすることはできません。

システムでは、ユーザーには 0..n のロールがあります。ユーザーが現在どのロールに属しているかに基づいて、システムは特定のデータ セットをそのユーザーに返します。ユーザーは特定のアクションを実行できますが、他のアクションは実行できません。

public class User
{
    public bool HasRole(string roleName)
    {
        return this.UserRoles.Any(r => r.Name == roleName);
    }

    public string Username { get; set; }

    public long? CurrentRoleId { get; set; }
    public Role CurrentRole { get; set; }

    public virtual IList<Role> UserRoles { get; set; }
}

public class Role
{
    public Role() { }

    public string Name { get; set; }
}

public class GetEventsQuery : IQuery<List<Event>>
{
    public List<Event> Query()
    {
        switch (this.user.CurrentRole.Name)
        {
            case "Administrator":
                UserIsNotInAdministratorRole();
                return repository.All.ToList();

            case "Supervisor":
                UserIsNotInSupervisorRole();
                return repository.All.Where(evnt => evnt.SupervisorId == this.user.RecordId).ToList();

            case "User":
                UserIsNotInUserRole();
                return repository.All.Where(evnt => evnt.UserId == this.user.RecordId).ToList();

            default:
                throw new Exception("GetEventsQuery Unknow exception.");
        }
    }

    private void UserIsNotInUserRole()
    {
        if (!this.user.HasRole("User"))
        {
            throw new NoUserRoleException("User does not have user role!");
        }
    }

    private void UserIsNotInSupervisorRole()
    {
        if (!this.user.HasRole("Supervisor"))
        {
            throw new NoSupervisorRoleException("User does not have supervisor role!");
        }
    }

    private void UserIsNotInAdministratorRole()
    {
        if (!this.user.HasRole("Administrator"))
        {
            throw new NoAdministratorRoleException("User does not have administrator role!");
        }
    }

    public GetEventsQuery(string username, IUserRepository userRepository, IEventRepository repository)
    {
        this.repository = repository;

        var userQuery = new GetUserQuery(username, userRepository);
        this.user = userQuery.Query();
    }

    private readonly User user;
    private readonly IEventRepository repository;
}

この switch ステートメントは、システムのすべての部分に表示されます。それをクラスにリファクタリングして単一の場所に配置する方法があった場合、それを保持してもかまいませんが、それを何度も繰り返すことは間違いなくコードの匂いです。私はこのプロジェクトを始めたばかりなので、オブジェクト階層を設計したり、この問題を解消するために大きな変更を加えたりするためのより良い方法があれば、私はそれを受け入れます。

4

5 に答える 5

1

この場合に必要なのは、FactoryパターンとStrategyパターンの組み合わせです。

戦略パターンは、アルゴリズムのファミリーを定義し、それぞれをカプセル化し、それらを交換可能にします。戦略により、アルゴリズムは、それを使用するクライアントとは独立して変化します。

Factory パターンは、具体的なクラスを指定せずに、関連オブジェクトまたは依存オブジェクトのファミリを作成するためのインターフェイスを提供します。

上記を一緒に使用すると、必要なすべての機能を提供する完全に拡張可能なクラスを作成できます...

これが役立つことを願っています。

于 2013-04-08T14:53:01.427 に答える