繁体   English   中英

持久层和业务逻辑调用C#的多态问题

[英]Polymorphism issue with persistence layer and business logic call c#

我实际上正在学习多态。 我已经使用DAO模式将业务逻辑与持久层完全分离,但是现在当我尝试访问持久层中的业务数据时遇到了一个问题。

我给你举个简单的例子

public class A
{

}

public class B : A
{

}

public class C : A
{

}

public class D : A
{

}

class Program
{
    protected virtual void Main(string[] args)
    {
        List<A> alist = new List<A>
        {
            new B(),
            new C(),
            new D()
        };

        PersistenceLayer persistenceLayer = new PersistenceLayer();
        foreach (A a in alist)
        {
            persistenceLayer.Foo(a); // can't call it
        }


    }

    public class PersistenceLayer
    {
        public void Foo(B b)
        {
            Console.WriteLine("is B");
        }

        public void Foo(C c)
        {
            Console.WriteLine("is c");
        }

        public void Foo(D d)
        {
            Console.WriteLine("is d");
        }
    }
}

我需要遍历泛型类,即列表形式中的类,这是我可以通过业务类控制器获得的类。 现在要获取子类类型并调用适当的方法,我需要为下一个更改foreach。

foreach (A a in alist)
{
    if (a is B b)
    {
        persistenceLayer.Foo(b);
    }
    else if (a is C c)
    {
        persistenceLayer.Foo(c);
    }
    else if (a is D d)
    {
        persistenceLayer.Foo(d);
    }
}

所以现在可以正常工作了,但是我讨厌开关或ifs检查类型和调用方法,因为现在我有3个子类,但是20个子类型会发生什么呢?

是否有任何方法可以执行此操作而不进行ifs或switch? 可能有某种模式吗?

这看起来像是Visitor模式的完美用例。

public interface IPersistenceLayer
{
    // These methods could all be called 'Foo' without the 'A' 'B' or 'C' suffix, but I've appended it to make it clear which method is being called
    void FooB(B b);
    void FooC(C c);
    void FooD(D d);
}

// I've made 'A' abstract, because in your example there is no 'Foo(A a)' method so this can't provide a default 'Foo' implementation
public abstract class A
{
    public abstract void Foo(IPersistenceLayer persistenceLayer);
}

public class B : A
{
    public override void Foo(IPersistenceLayer persistenceLayer) => persistenceLayer.FooB(this);
}

public class C : A
{
    public override void Foo(IPersistenceLayer persistenceLayer) => persistenceLayer.FooC(this);
}

public class D : A
{
    public override void Foo(IPersistenceLayer persistenceLayer) => persistenceLayer.FooD(this);
}

public static class PersistenceLayerExtensions
{
    public static void Foo(this IPersistenceLayer persistenceLayer, A a) => a.Foo(persistenceLayer);
}

class Program
{
    public static void Main(string[] args)
    {
        List<A> alist = new List<A>
        {
            new B(),
            new C(),
            new D()
        };

        PersistenceLayer persistenceLayer = new PersistenceLayer();
        foreach (A a in alist)
        {
             persistenceLayer.Foo(a);
        }
    }
}

您可以在持久层中添加一个接受类型A的函数,然后检查它是哪一个并调用适当的函数。 这样比较好,因为您不必每次都检查函数内部的哪一个,只需检查一次。

它看起来像这样:

public void Foo(A a)
{
  if(a.GetType() == typeof(B))
  {
    Foo((B) a);
  }
  else if(a.GetType() == typeof(C))
  {
    Foo((C) a);
  }
  else if(a.GetType() == typeof(D))
  {
    Foo((D) a);
  }
}

因此,这基本上是一个通用方法,您可以使用任何继承自A的对象进行调用。

此解决方案符合DRY(请勿重复自己)原则。

如果该想法只是打印哪一个,您也可以按照以下步骤进行:

public void Foo(A a)
{
  Console.WriteLine($"is {a.GetType().toString()}");
}

我在这里使用了字符串插值 ,但是您也可以不用,如果您问我,它看起来会更好一些

如果您是个花哨的人,还可以按如下所示将函数添加到类中:

public abstract class A
{
  public abstract void Foo();
}

public class B : A
{
  public override void Foo()
  {
    Console.WriteLine("is b");
  }
}

public class C : A
{
  public override void Foo()
  {
    Console.WriteLine("is c");
  }
}

public class D : A
{
  public override void Foo()
  {
    Console.WriteLine("is d");
  }
}

请注意,我在这里将A类抽象化了,因为您实际上并没有创建A本身的实例,所以您可以将A类抽象化,并且只为实际函数提供一个“模板”,继承成员随后将其覆盖

希望这对您有所帮助,祝您在C#旅途中一切顺利

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM