Ограничение возможностей пользователя на основе ролей - PullRequest
1 голос
/ 04 июля 2011

Сценарий

Я строю систему, в которой каждый предмет проверяют 2 разных человека.Всякий раз, когда первый рецензент сохраняет рецензию на предмет, тогда второй чекер может завершить свою индивидуальную рецензию.Если я отправил первый отзыв и снова открыл элемент, то элемент переводится в состояние только для чтения, поскольку вы не можете просмотреть свою собственную работу.Кроме того, первый рецензент может перевести элемент в состояние ожидания, если требуется дополнительная информация, чего не может сделать вторая рецензия.Каждый пользователь получает определенный список проверяющих каждый раз, когда выбирает элемент из списка.

То, что у меня есть до сих пор

Каждый раз, когда элемент загружается в редактор, человеку присваивается один из 2Роли, InitialReviewer или SecondReviewer.

public class Reviewer
{
    public void AddReview(string review) { }
}

public class InitialReviewer : Reviewer, ICanPutIntoPendingState
{
    public void PutIntoPendingState(string pendingState) { }
}

public class SecondReviewer : Reviewer
{
    // Just use base class to add review
}

public class ReviewerService
{
    private readonly Reviewer _reviewer;

    public void AddReview(string review)
    {
        _reviewer.AddReview(review);
    }

    public void PutIntoPendingState(string pendingState)
    {
        _reviewer.PutIntoPendingState(pendingState);
    }
}

Урезанная версия моего редактора.

public class Editor
{
    private readonly ReviewerService _reviewerService;

    public Editor(ReviewerService reviewerService)
    {
        _reviewerService = reviewerService;
    }

    public void SaveCommand()
    {
        if(user chose a pending state && _reviewerService.Reviewer is ICanPutIntoPendingState) // Pending state is a dropdown.
            _reviewerService.PutIntoPendingState("pending state");
        else // the user made a complete review
            _reviewerService.AddReview("user review");
    }
}

Проблема

У меня возникла проблемачто я не могу избежать наличия логики внутри Save() из Editor класса, который там не принадлежит.

Вопрос

Как мне избавиться от логики внутрифункции Save() из класса Editor?Похоже, что это нарушает принцип SRP.Думаю, большая проблема в том, чтобы проверить, относится ли текущий объект рецензента к типу ICanPutIntoPendingState.

Обратите внимание, что я опустил всю логику, потому что там совсем немного.

Ответы [ 2 ]

3 голосов
/ 04 июля 2011

Было бы недостаточно предоставить ReviewerService один метод Save (), который внутренне вызывает один метод Save (), на данный момент абстрактного класса Reviewer, для которого конкретная реализация метода Save () осуществляется в InitialReviewer и SecondReviewer. , Таким образом, вы продвигаете логику принятия решений в классы с конкретной реализацией. Надеюсь, это поможет.

2 голосов
/ 05 июля 2011

Возможно, вам следует подумать о переносе бизнес-логики из класса Reviewer в ReviewerService. Тогда простая реализация будет выглядеть примерно так:

    public abstract class Reviewer
{
    public abstract bool CanPutIntoPendingState { get; }

}

public class InitialReviewer : Reviewer
{
    public override bool CanPutIntoPendingState 
    {
        get
        {
            return true;
        }
    }
}

public class SecondReviewer : Reviewer
{
    public override bool CanPutIntoPendingState 
    {
        get
        {
            return false;
        }
    }
}

public class ReviewerService
{
    private readonly Reviewer _reviewer;

    public void AddReview(string review)
    {
        // do add review logic here
    }


    public void PutIntoPendingState(string pendingState) 
    { 
        if (_reviewer.CanPutIntoPendingState ) 
        {
            // do PutIntoPendingState logic here
        }
    }
}

public class Editor
{
    private readonly ReviewerService _reviewerService;

    public Editor(ReviewerService reviewerService)
    {
        _reviewerService = reviewerService;
    }

    public void SaveCommand()
    {
        if(user chose a pending state) // Pending state is a dropdown.
            _reviewerService.PutIntoPendingState("pending state");
        else // the user made a complete review
            _reviewerService.AddReview("user review");
    }
}

Можно также рассмотреть возможность предоставления только одной функции службе рецензирования, которая принимает модель ввода. Служба несет ответственность за проверку входных данных и принятие соответствующих мер. Примерно так:

public class ReviewerService
{
    private readonly Reviewer _reviewer;

    public void StoreReview(ReviewModel model)
    {
        // validate input here

        // do business logic here
        if (model.IsPendingState && _reviewer.CanPutIntoPendingState)
        {
            this.PutIntoPendingState("pending state");
        }
        else
        {
            this.AddReview(model.Review);
        }

    }

    private void AddReview(string review)
    {
        // do add review logic here
    }

    private void PutIntoPendingState(string pendingState)
    {

       // do PutIntoPendingState logic here

    }
}

public class ReviewModel
{
    public string Review { get; set; }
    public bool IsPendingState { get; set; }
}

public class Editor
{
    private readonly ReviewerService _reviewerService;

    public Editor(ReviewerService reviewerService)
    {
        _reviewerService = reviewerService;
    }

    public void SaveCommand()
    {
        ReviewModel model = new ReviewModel() {Review="user review",IsPendingState=user chose a pending state };

        _reviewerService.StoreReview(model);
    }
}
...