Вопрос о шаблоне объекта роли - PullRequest
6 голосов
/ 28 июня 2011

Я смотрю на статью Мартина Фаулера под названием Работа с ролями .В ней Фаулер выделяет три основные стратегии работы с ролями для человека в организации (т. Е. Сотрудника, инженера, менеджера, продавца), которые включают подтип роли, объект роли и отношения роли.

* 1004написанный в 1997 году, он, безусловно, старый, и, будучи «рабочим проектом», он также имеет некоторые ошибки, которых в противном случае не было бы.Я запутался, просматривая пример Ролевого Объекта, через который он проходит, и включил мою интерпретацию c # некоторых его java-кодов ниже.

У меня есть три вопроса:
(1) есть многоИдентификация типа выполняется со строками, которые, кажется, должны быть заменены обобщениями, но я пока не могу понять, как это сделать.Как бы вы реализовали этот код с использованием обобщений?
(2) JobRole находится в коде как строковое имя для типа, но оно не определено специально с остальной частью кода.Я не могу сказать, является ли это базовым классом для PersonRole или нет.Какое определение для JobRole?Похоже ли модульный тест на правильный пример использования шаблона?
(3) Есть ли у кого-нибудь ссылки на более позднюю реализацию и пример использования объекта роли?

Cheers,
Berryl

public class PersonWithRoles : Person
{
    private readonly IList<PersonRole> _roles = new List<PersonRole>();

    public static PersonWithRoles CreatePersonWithRoles(string identifierName) {
        ...
    }

    public void AddRole(PersonRole role) { _roles.Add(role); }

    public PersonRole RoleOf(string typeName) { return _roles.FirstOrDefault(x => x.HasType(typeName)); }
}

public class PersonRole
{
    public virtual bool HasType(string typeName) { return false; }
}

public class Salesman : PersonRole
{
    public override bool HasType(string typeName)
    {
        if (typeName.Equals("Salesman", StringComparison.InvariantCultureIgnoreCase)) return true;
        if (typeName.Equals("JobRole", StringComparison.InvariantCultureIgnoreCase)) return true;

        return base.HasType(typeName);
    }

    public int NumberOfSales { get; set; }

}

[TestFixture]
public class RoleUsageTests
{
    [Test]
    public void Test() {
        var p = PersonWithRoles.CreatePersonWithRoles("Ted");
        var s = new Salesman();
        p.AddRole(s);

        var tedSales = (Salesman) p.RoleOf("Salesman");
        tedSales.NumberOfSales = 50;
    }
}

Ответы [ 2 ]

5 голосов
/ 28 июня 2011

Я убежден, что эти типы приложений являются хорошими кандидатами для использования шаблона проектирования декоратора , в котором есть базовый класс Person, а затем каждая роль расширяет этот базовый класс.Базовый класс не имеет деклараций разрешений - должны только классы ролей, которые расширяют person.

Извините, что расплывчато, но я надеюсь, что вы получите то, что я пытаюсь описать.

class programmer {
 name ...
 email ...
 seat location ...
}

class html_coder extends programmer {
 canCodeHTML ...
}

class script_coder extends programmer {
 canCodeHTML ...
 canCodeJavascript ...
}

class senior_developer extends programmer {
 canCodeHTML ...
 canCodeJavascript ...
 canAccessDatabase ...
 canEditProjectArchitectureFiles ...
 canWearTennisShoesToWork...
}

все это расширяет базовый класс программиста ... обратите внимание, что класс программиста не объявляет права ... просто свойства

1 голос
/ 08 июля 2011
  1. Обобщения в c # могут помочь сделать более аккуратную реализацию
  2. JobRole - это подтип PersonRole и супертип для конкретных заданий

Я все еще хотел бы видеть примеры использования, так как один из пунктов Фаулера об этом шаблоне заключается в том, что гибкость печати достигается за счет двухэтапного шаблона использования.Реализация этого с использованием шаблона Decorator не меняет этого.Например, для работы с человеком в роли продавца сначала нужно получить экземпляр человека, а затем найти роль продавца.

Приветствия,
Берриль

public class Person
{
    public FullName FullName  { get; set; }
    public IList<IRole> Roles { get; private set; }

    public Person(FullName fullName) => FullName = fullName;

    public IRole GetRoleOf<T>() where T: IRole => 
        Roles.FirstOrDefault(x => x.HasType(typeof(T)));
    public void AddRole(IRole role)    => Roles.Add(role);
    public bool RemoveRole(IRole role) => Roles.Remove(role);

}

public interface IRole
{
    bool HasType(Type type);
}

public abstract class Role : IRole
{
    public virtual bool HasType(Type type) { return false; }
}

// Base type for any type of role for a person.
public class PersonRole : Role
{
    public override bool HasType(Type type) => type.Equals(typeof(PersonRole));
}

// Base type for any type of role for a person.
public class JobRole : Role
{
    public override bool HasType(Type type) 
    {
        if (type.Equals(GetType())) return true;
        return base.HasType(type);
    }
}

// Behavior specific to a salesman
public class Salesman : JobRole, ISalesman
{
    public override bool HasType(Type type)
    {
        if (type.Equals(GetType())) return true;
        return base.HasType(type);
    }

    public int NumberOfSales { get; set; }
}

[TestFixture]
public class JobRoleTests : BaseTestFixture
{
    private PersonEx _person;

    protected override void OnFixtureSetUp() 
    {
        _person = new PersonEx(new OneNameFullName("schmuck"));
        // can be a Salesman
        _person.AddRole(new Salesman());
    }

    [Test]
    public void Salesman_CanGet() 
    {
        var salesman = _person.GetRoleOf<Salesman>() as Salesman;
        Assert.That(salesman, Is.Not.Null);
        salesman.NumberOfSales = 50;
        Assert.That(salesman.NumberOfSales, Is.EqualTo(50));
    }
}
...