2011-08-03 9 views
2

以下のモデル(右)のPartyRoleConstraintsクラスがこの質問の対象です。ジェネリックはこのデザインを改善できますか?

enter image description here

アイデアは、クライアントがRoleTypeでパーティーを関連付けるしようとすると、それが関連しているから与えられたパーティーを防ぐ必要がある任意の制約を持っている場合、RoleTypeが見ているということです。パーティーは、個人と組織の両方のスーパータイプです。一般的な制約はタイプによってだろう

public interface IRoleConstraint<in T> 
{ 
    Func<T, bool> IsSatisfied { get; } 
    string UnsatisfiedDescription { get; } 
    bool CanAddRole(T instance); 
} 

はここで後に私は完全に一般的なインタフェースです。だから私は "夫"の役割のタイプを持っている場合、私はパーティーのインスタンスが人であることを確認したい。ここで私はこれを行うことができます証明いくつかの実装とテストケースである:私は党のサブタイプの属性に基づいてルールを設定したい場合は

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

私は当たっています問題があります。たとえば、私は夫の性別を男性にします。私のように、キャストでこれを行うことができます。

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

質問(ついに!)である:私はキャストを避けるために、ジェネリックを使用し、そうであれば、どのようにできますか?

答えて

1

はい、キャストを取り除くことはできますが、 "Person"はどこかに指定する必要があります。要件や制約についてもっと知らなくても、「ベストプラクティス」を提案するのは難しいです。さらに制限を許可するようにPartyRoleConstrainedToTypeをtweekことであろう

var mustBeMale = PartyRoleConstraint.For<Person>(p => p.Gender == ...); 

別のオプション:1つのオプションは、ようなものになるだろう。そして例は次のようになります。あなたがどこかPersonを指定する必要がありますが、さまざまなオプションが素敵構文が作成する:

var combinedConstraint = new PartyRoleConstrainedToType<Person>().MustSatisfy(p => p.Gender == ...); 

としては、前に述べました。いい意味は、あなたの要件とユースケースに依存します。

+0

これは、いくつかのアプリケーションにまたがるフレームワークタイプのlibの一部であるため、私は実際にクラスタイプのparamsの一部にすることができるのだろうかと思っていました。一般的な流暢なタイプのものは考えていませんでした。それはあなたが言っていると思います。それはのために入れ子にされたクラスですか?あなたがそれをより良く見るのを助けるために、いくつかの行のコードを追加してください。 – Berryl

+0

例えば、新しいMustMatchGender(Gender.Male)のような与えられた制約をサブクラス化することは、特定のドメインでより一般的な制約に最も適していますが、より良い提案も理解したいと思います。乾杯 – Berryl