【问题标题】:Role Object pattern question角色对象模式问题
【发布时间】:2011-06-27 22:44:22
【问题描述】:

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

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

我有三个问题:
(1) 有很多类型识别是用字符串完成的,看起来应该可以用泛型替换,但我还不知道如何做到这一点。您将如何使用泛型实现此代码?
(2) JobRole 在代码中作为类型的字符串名称,但没有在其余代码中专门定义。我不知道这是否是 PersonRole 的基类。 JobRole的解释是什么?单元测试看起来像模式用法的正确示例吗?
(3) 有没有人有任何关于使用角色对象的最新实现和示例的链接?

干杯,
浆果

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

【问题讨论】:

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


    【解决方案1】:

    我相信这些类型的应用程序非常适合使用 装饰器设计模式,其中有一个 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...
    }
    

    这些都扩展了程序员基类...注意程序员类没有声明权限...只是属性

    【讨论】:

    • 认为是这样。您能否草拟一些示例代码或给我一个显示它的链接?干杯
    • 来自 Fowler 的同一篇论文:“这种模式的一个有用的变体是使角色对象成为核心对象的装饰器。这意味着只使用员工个人特征的客户可以处理单个对象而不需要了解角色对象的使用。代价是当人员的界面发生变化时,所有角色都需要更新。有关如何执行此操作的更多详细信息,请参阅 [Bäumer 等人]。 "
    • 这是 Fowler 引用的 link to Baumer's work。它概述了由 (3) 个主要参与者组成的模式;使用您的示例将有一个抽象的程序员,它定义了程序员的接口以及管理角色的接口。然后是一个 ProgrammerCore,它实现了 Programmer 接口和角色管理。最后有一个 ProgrammerRole 装饰 ProgrammerCore 的一个实例。 HtmlCoderRole 和 SeniorDevRole 是 ProgrammerRole 的子类。干杯
    【解决方案2】:
    1. c# 中的泛型有助于实现更简洁的实现
    2. JobRolePersonRole 的子类型,是特定工作的超类型

    我仍然希望看到使用示例,因为 Fowler 关于这种模式的观点之一是打字灵活性是以牺牲两步使用模式为代价的。使用装饰器模式实现这一点不会改变这一点。例如,要与销售员角色中的人一起工作,首先需要获取一个人的实例,然后找到销售员的角色。

    干杯,
    浆果

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

    【讨论】:

      猜你喜欢
      • 2021-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-31
      • 2011-08-10
      • 2016-07-12
      • 2019-08-20
      • 2011-03-06
      相关资源
      最近更新 更多