简体   繁体   English

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

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

I am actually learning polymorphism. 我实际上正在学习多态。 I have my business logic completely decoupled of the persistence layer using the DAO pattern, but now I am facing a problem when I am trying to access the business data in the persistence layer. 我已经使用DAO模式将业务逻辑与持久层完全分离,但是现在当我尝试访问持久层中的业务数据时遇到了一个问题。

I will bring you a simple example 我给你举个简单的例子

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

I need to loop around the generic class, that is what I have in a list form, that is what I can obtain by my business class controller. 我需要遍历泛型类,即列表形式中的类,这是我可以通过业务类控制器获得的类。 Now to get the subclass type and call the appropriate method I need to change the foreach for the next. 现在要获取子类类型并调用适当的方法,我需要为下一个更改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);
    }
}

So now is it working, but I hate the switch or the ifs checking the type and calling methods because now I have 3 subclasses, but what happens with 20 subtypes? 所以现在可以正常工作了,但是我讨厌开关或ifs检查类型和调用方法,因为现在我有3个子类,但是20个子类型会发生什么呢?

Is there any way to do this without doing this ifs or switch? 是否有任何方法可以执行此操作而不进行ifs或switch? Is there some pattern maybe? 可能有某种模式吗?

This looks like a perfect use case for the Visitor pattern . 这看起来像是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);
        }
    }
}

You could add a function to the Persistence layer that accepts the type A, then checks which one it is and calls the appropriate one. 您可以在持久层中添加一个接受类型A的函数,然后检查它是哪一个并调用适当的函数。 This is better since you don't have to check which one it is every time, only once inside of the function. 这样比较好,因为您不必每次都检查函数内部的哪一个,只需检查一次。

It would look something like this: 它看起来像这样:

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

so this is basically a general method which you can call with any object inheriting from A. 因此,这基本上是一个通用方法,您可以使用任何继承自A的对象进行调用。

This is solution complies with the DRY (Don't Repeat Yourself) principles. 此解决方案符合DRY(请勿重复自己)原则。

If the idea is only to print which one it is you could also do it as follows: 如果该想法只是打印哪一个,您也可以按照以下步骤进行:

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

I used string interpolation here but you can also go without, it just looks a bit better if you ask me 我在这里使用了字符串插值 ,但是您也可以不用,如果您问我,它看起来会更好一些

And if you are a fancy man you can also add the function to the classes themselves as follows: 如果您是个花哨的人,还可以按如下所示将函数添加到类中:

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

Note that I made class A abstract here, since you don't actually make instances of A itself you can make the class abstract and only provide a 'template' for the actual functions which the inheriting members then override . 请注意,我在这里将A类抽象化了,因为您实际上并没有创建A本身的实例,所以您可以将A类抽象化,并且只为实际函数提供一个“模板”,继承成员随后将其覆盖

I hope this helped, Good luck on your c# journey 希望这对您有所帮助,祝您在C#旅途中一切顺利

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

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