[英]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.