下面模型(右侧)中的 PartyRoleConstraints 类是此问题的主题。
这个想法是,当客户端尝试将 Party 与 RoleType 相关联时,RoleType 会查看它是否有任何 Constraints 应该阻止给定的 Party 被关联。 Party 是 Person 和 Organization 的父类(super class)型。
这是我想要的完全通用的界面:
public interface IRoleConstraint<in T>
{
Func<T, bool> IsSatisfied { get; }
string UnsatisfiedDescription { get; }
bool CanAddRole(T instance);
}
一个常见的约束是按类型。因此,如果我的角色类型是“丈夫”,那么我想确保 Party 实例是一个人。这是一些实现和测试用例,证明我可以做到这一点:
public class RoleConstraint<T> : IRoleConstraint<T>
{
public RoleConstraint(Func<T, Boolean> isSatisfied, string unsatisfiedDescription) {
if (isSatisfied == null) throw new ArgumentNullException("isSatisfied");
if (unsatisfiedDescription == null) throw new ArgumentNullException("unsatisfiedDescription");
IsSatisfied = isSatisfied;
UnsatisfiedDescription = unsatisfiedDescription;
}
public Func<T, bool> IsSatisfied { get; protected set; }
public string UnsatisfiedDescription { get; protected set; }
public bool CanAddRole(T instance) { return IsSatisfied.Invoke(instance); }
}
public class PartyRoleConstraint : RoleConstraint<Party>
{
public PartyRoleConstraint(Func<Party, bool> isSatisfied, string unsatisfiedDescription) : base(isSatisfied, unsatisfiedDescription) { }
}
public class PartyRoleConstrainedToType<TRequired> : PartyRoleConstraint where TRequired : Party
{
private static readonly string _unsatisfiedDescription
= string.Format("This role requires a Party instance to be a {0}", typeof(TRequired).Name);
private static readonly Func<Party, bool> _isSatisfied = instance => instance.GetType().Equals(typeof(TRequired));
public PartyRoleConstrainedToType() : base(_isSatisfied, _unsatisfiedDescription) { }
}
[Test]
public void Constraints_IfTypeConstraint_and_InstanceDoesNotMatch_False()
{
var sony = new Organization("Sony Corporation");
var constraint = new PartyRoleConstrainedToType<Person>();
_husbandRoleType.AddConstraint(constraint);
Assert.That(_husbandRoleType.CanAddRole(sony), Is.False);
}
我遇到的问题是,如果我想根据 Party 子类型的属性设置规则。例如,我希望丈夫的性别是男性。我可以通过 Actor 阵容做到这一点,因为:
[Test]
public void Constraints_IfConstraintConditionIsNotMet_False()
{
_husbandRoleType.AddConstraint(new PartyRoleConstrainedToType<Person>());
Assert.That(_husbandRoleType.CanAddRole(_arthur), Is.True);
//**** here is the cast **** //
var mustBeMale = new PartyRoleConstraint(p => ((Person)p).Gender == Gender.Male, "the husband must be male.");
_husbandRoleType.AddConstraint(mustBeMale);
Assert.That(_husbandRoleType.CanAddRole(_arthur), Is.False);
_arthur.Gender = Gender.Male;
Assert.That(_husbandRoleType.CanAddRole(_arthur), Is.True);
}
问题(终于!)是:我可以使用泛型来避免强制转换吗?如果可以,如何避免?
最佳答案
是的,你可以去掉类型转换,但你必须在某处指定“Person”。在不了解您的要求和限制的情况下,很难提出这样做的“最佳地点”。一种选择是这样的:
var mustBeMale = PartyRoleConstraint.For<Person>( p => p.Gender == ...);
另一种选择是调整 PartyRoleConstrainedToType
以允许进一步的限制。示例可能如下所示:
var combinedConstraint = new PartyRoleConstrainedToType<Person>().MustSatisfy(p => p.Gender == ...);
如前所述:您必须在某处指定 Person
,但有不同的选项可以创建不错的语法。什么是好,取决于您的要求和用例。
关于c# - 泛型可以改进这种设计吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6931493/