微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何创建工厂以创建接受更多派生类型参数的派生对象

如何解决如何创建工厂以创建接受更多派生类型参数的派生对象

我在为基于公共的类系列的工厂设计合适的解决方案时遇到了问题。我有一个名为 Verifier 的类,该类将只有方法 Verify ,它接受 Specification 的实例作为参数

public abstract class Verifier 
{
    public virtual bool Verify(Specification spec) 
    {
        //does the common job
        return true; //or false
    }
}

然后我有一组具体的验证器

public abstract class FirstVerifier : Verifier
{
    public override bool Verify(Specification spec) 
    {
       //does the job,maybe even calls for base or maybe not
       return true; 
    }
}

public abstract class SecondVerifier : Verifier
{
    public override bool Verify(Specification spec) 
    {
       //does the job,maybe even calls for base or maybe not
       return true; 
    }
}

然后我有一个不错的工厂,它返回一个合适的实例:

public class VerifierFactory 
{
    public static Verifier Create(string type) //not actually a string,but does not matter
    {
        switch (type) 
        {
            case "First": return new FirstVerifier();
            case "Second": return new SecondVerifier();
            default: throw new Exception();
        } 
    }
}

现在我有一个要求,即验证者可以验证的不是规范的实例,而是规范的派生类型,例如:

public abstract class FirstVerifier : Verifier
{
    public override bool Verify(SpecificationOne spec)  //SpecificationOne derives from Specification
    {
       //does the job,maybe even calls for base or maybe not
       return true; 
    }
}

public abstract class SecondVerifier : Verifier
{
    public override bool Verify(SpecificationTwo spec) //SpecificationOne derives from Specification
    {
       //does the job,maybe even calls for base or maybe not
       return true; 
    }
}

这显然不会编译,我不想做这样的伎俩:

public abstract class FirstVerifier : Verifier
{
    public override bool Verify(Specification spec)
    {
       var realSpecification = spec as SpecificationOne;
       if(realSpecification == null)
          throw new Exception();
       // do job
    }
}

我正在考虑一种解决方案(可能是通用的),其中我的工厂返回正确的类型,然后在验证方法中接受正确的类型,这样我就可以使用我的工厂创建验证程序并调用验证,如下所示:

specifications.Select(s => VerifierFactory.Create(typeof(s)).Verify(s))

解决方法

我认为您可以使用泛型方法。例如:

public abstract class Verifier 
{
    public virtual bool Verify<T>(T  spec) where T: Specification
    {
        //does the common job
        return true; //or false
    }
}

或者你可以使用泛型类,例如:

创建基础 Specification

public class Specification
{
    //some properties,fields and etc
}

并从基础 Specification 类继承您的其他规范

public class SpecificationOne : Specification
{
    //some properties,fields and etc
}


public class SpecificationTwo : Specification
{
    //some properties
}

创建基 Verifier 类后,它是泛型类。

public abstract class Verifier<T> where T : Specification
{
    public virtual bool Verify(T spec)
    {
        //does the common job
        return true; //or false
    }
}

并从基 Verifier<T> 类继承其他验证器类。 这些类必须不是抽象的,因为我们将在 VerifierFactory 中创建实例。例如:

public class FirstVerifier : Verifier<SpecificationOne>
{
    public override bool Verify(SpecificationOne spec)
    {
        var baseResult = base.Verify(spec);

        //some logic

        return baseResult;
    }
}

public class SecondVerifier : Verifier<SpecificationTwo>
{
    public override bool Verify(SpecificationTwo spec)
    {
        var baseResult = base.Verify(spec);

        //some logic

        return baseResult;
    }
}

您可以像下面这样创建 VerifierFactory

public class VerifierFactory
{
    public static Verifier<T> Create<T>(T spec) where T : Specification
    {
        if (spec.GetType() == typeof(SpecificationOne))
            return new FirstVerifier() as Verifier<T>;

        if (spec.GetType() == typeof(SpecificationTwo))
            return new SecondVerifier() as Verifier<T>;

        //and etc...
        // I think you project must have one default Verifier class for else case
    }
}

最后,您可以使用如下所示的 linq 查询:

specifications.Select(s => VerifierFactory.Create(s).Verify(s))
,

考虑这个解决方案。从通用的基本验证器开始,并提供验证 Specification 部分的默认实现,然后调用子类的实现来验证 T 部分。

public abstract class Verifier<T> where T : Specification 
{
    // in most cases you probably wouldn't override this
    // in subclasses,but you could if necessary
    public virtual bool Verify(Specification spec) 
    {
        if (!VerifyCommon(spec)) return false;
        return VerifyImplementation((T)spec);
    }

    protected abstract bool VerifyImplementation(T spec);

    protected bool VerifyCommon(Specification spec)
    {
        //does the common job
        return true; //or false
    }
}

你的工厂根本不需要改变。您的子类将在每种情况下实现抽象 VerfifyImplementation

public class FirstVerifier : Verifier<SpecificationOne>
{
    protected override bool VerifyImplementation(SpecificationOne spec)
    {
       // do job
       return ...;
    }
}

您的 select 必须更改为类似的内容

specifications.Select(s => VerifierFactory.Create(s.GetType()).Verify(s))

此解决方案的优点是在每种情况下应用相同的验证模式,并避免在子类中进行强制转换(尽管您确实在基类中进行了强制转换)。

然而,此解决方案有一个缺点,即 FirstVerifier 可能接受 SpecificationVerify(Specification) 的错误子类。要解决此问题,您可以将基本验证器更改为

public abstract class Verifier<T> where T : Specification 
{
    public virtual bool Verify(T spec) 
    {
        if (!VerifyCommon(spec)) return false;
        return VerifyImplementation(spec);
    }

    protected abstract bool VerifyImplementation(T spec);

    protected bool VerifyCommon(Specification spec)
    {
        //does the common job
        return true; //or false
    }
}

但这意味着您的 select 将不得不执行一些动态魔法以确保可以正确调用 Verify 方法:

specifications.Select(s => VerifierFactory.Create(s.GetType()).Verify((dynamic)s))

此实现消除了 Verify 内部的强制转换并确保了类型安全,但动态调用 Verify 方法的成本(可能可以忽略不计)。

这两种实现的好处是它们

  • 避免调用 base.Verify() ,当子类的开发人员忘记调用 base.Verify() 时,这有时会导致错误。
  • 可以对 Specification 的异构列表进行操作。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。