包装器类,包装了多种类型和组成模式

时间:2018-11-05 11:42:32

标签: c# design-patterns composition

我有一个如下的包装器类,用于包装TypeA,TypeB和TypeC。

class Wrapper
{
    class TypeA {get;set;}
    class TypeB {get;set;}
    class TypeC{get;set;}
}

因此,现在的呼叫者代码不好。我必须根据类似的不同类型来确定:

Wrapper wrapper = new Wrapper(TypeA);

if (wrapper.TypeA != null && wrapper.TypeA.SomeProperty != null)
{
    return wrapper.TypeA.SomeProperty;
}

if (wrapper.TypeB != null && wrapper.TypeB.SomeProperty != null)
{
    return wrapper.TypeB.SomeProperty;
}

Wrapper cwrapper = new Wrapper(TypeA, TypeB);

if (wrapper.TypeA == null && wrapper.TypeB != null && wrapper.TypeB.SomeProperty != null)
{
    return wrapper.TypeB.SomeProperty;
}

如您所见,调用者代码还必须检查TypeA和TypeB以及TypeC的组合。 我当时只是想使用一些构图并公开一些策略或属性,这些属性将给我想要的对象,例如:

wrapper.As<TypeA>()之类的。有什么建议可以避免调用方进行多次检查吗?

3 个答案:

答案 0 :(得分:2)

为什么?您使用的是Adapter Pattern类,您的班级应该看起来像

class Wrapper
{
    public TypeA A {get;set;}
    public TypeB B {get;set;}
    public TypeC C{get;set;}

  public Wrapper(TypeA A, TypeB B, TypeC C)
  {
   this.A = A;
   // rest initialization
  }
}

您现在可以说

Wrapper w = new Wrapper(new TypeA(), ...);
w.A.SomeProperty;

同样,可以使用 Null Propagation 运算符代替

,而不是使用空检查if条件
wrapper?.TypeA?.SomeProperty;

您可以一起使用 Null Coalesce 运算符,以在属性为null的情况下返回属性的默认值

wrapper?.TypeA?.SomeProperty ?? string.Empty;

答案 1 :(得分:0)

我建议您在构造函数中使用一些保护子句,并使用一些只读属性来整理所有内容

class Wrapper
{
    public TypeA A {get;}
    public TypeB B {get;}
    public TypeC C {get;}

  public Wrapper(TypeA A, TypeB B, TypeC C)
  {
   this.A = A ?? throw new ArgumentNullException(nameof(A));
   this.B = B ?? throw new ArgumentNullException(nameof(B));
   this.C = C ?? throw new ArgumentNullException(nameof(C));
  }
}

现在,除非有人通过反射进行了愚蠢的操作,否则您的A,B,C属性不能为null。因此,您无需进行空检查。

然后您可以使用null运算符来整理最后几位

wrapper.A.someProperty ?? string.Empty

答案 2 :(得分:0)

就像您建议的那样,我将使用一种强制转换方法。像这样:

class Wrapper {
    bool TryGet<T> (out T wrappedObj) {
        if (typeof(T) == ClassA.GetType()) {
            wrappedObj = objA;
        }
        //...
        return wrappedObj != null;
    }

    // or
    bool TryGet<T,U>(Func<U> propGetter, out U prop) {
        if (TryGet<T>(out T wrappedObj)) {
            prop = propGetter(wrappedObj);
            return true;
        }
        prop = default(U); 
        return false;
    }
}

if (wrapper.TryGet<ClassA>(out ClassA obj)) {
//...
}

//or

if (wrapper.TryGet<ClassA, String>(aObj =>  aObj?.SomeProperty, out String prop) {

}