角色对象模式问题

时间:2011-06-27 22:44:22

标签: c# design-patterns domain-driven-design

我正在看Martin Fowler所写的一篇名为Dealing With Roles的论文。在其中,Fowler为组织中的人员(即员工,工程师,经理,推销员)处理角色分为三种基本策略,包括角色子类型,角色对象和角色关系。

1997年写完它肯定是旧的,作为一个“工作草案”它也有一些错误,否则不会存在。我很困惑看到他经历的一个角色对象的例子,并且包含了我对他下面的一些Java代码的c#解释。

我有三个问题:
(1)有许多类型标识用字符串完成,看起来它应该可以用泛型替换,但我还无法掌握如何做到这一点。您将如何使用泛型实现此代码? (2)JobRole在代码中作为类型的字符串名称,但没有使用其余代码明确定义。我不知道这是否是PersonRole的基类。 JobRole的定义是什么?单元测试看起来像是模式用法的正确示例吗? (3)是否有人与更近期的实施和使用角色对象的示例有任何联系?

干杯,
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 个答案:

答案 0 :(得分:5)

我相信这些类型的应用程序是使用装饰器设计模式的良好候选者,其中有一个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 :(得分:1)

  1. c#中的泛型可以帮助实现更简洁的实现
  2. JobRolePersonRole的子类型,是特定作业的超类型
  3. 我仍然希望看到使用示例,因为Fowler关于这种模式的观点之一是打字灵活性是以牺牲两步使用模式为代价的。使用Decorator模式实现此功能不会改变这一点。例如,要与Salesman角色中的Person一起工作,首先需要获取一个人的实例,然后找到Salesman的角色。

    干杯,
    Berryl

    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));
        }
    }