我实际上正在学习多态性。我已经使用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?可能有某种模式吗?
答案 0 :(得分:2)
这似乎是Visitor pattern的完美用例。
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);
}
}
}
答案 1 :(得分:0)
您可以在Persistence层中添加一个接受类型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()}");
}
我在这里使用过string interpolation,但您也可以不用,如果您问我,它看起来会好一点
如果您是个花哨的人,还可以按如下所示将函数添加到类中:
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 abstract,因为您实际上并没有创建A本身的实例,所以您可以使类抽象,而仅为实际函数提供一个“模板”,继承成员然后{ {3}}。
我希望这对您有帮助,祝您在C#旅途中一切顺利!