C# 如何避免强制转换到特定接口 背景信息
我有一组接口/类,如下所示。为了简单起见,想象更多的属性、集合等C# 如何避免强制转换到特定接口 背景信息,c#,interface,solid-principles,C#,Interface,Solid Principles,我有一组接口/类,如下所示。为了简单起见,想象更多的属性、集合等 接口IMaster { //一些性质 } 接口IB:IMaster { 字符串PropOnA{get;set} } 接口IC:IMaster { 字符串PropOnB{get;set} } B类:IB C类:集成电路 ... 这些合同旨在存储数据(在每种情况下,数据的格式略有不同)。有很多代码使用这些契约来获取数据、格式化数据、处理数据、编写数据等等。 我们开发了一个完整的库,通过反转控制,它看不到任何这些契约的具体实现(B,C
接口IMaster
{
//一些性质
}
接口IB:IMaster
{
字符串PropOnA{get;set}
}
接口IC:IMaster
{
字符串PropOnB{get;set}
}
B类:IB
C类:集成电路
...
这些合同旨在存储数据(在每种情况下,数据的格式略有不同)。有很多代码使用这些契约来获取数据、格式化数据、处理数据、编写数据等等。
我们开发了一个完整的库,通过反转控制,它看不到任何这些契约的具体实现(B,C),并允许用户对每个契约使用我们的“默认实现”,或者只加载他们自己的契约。我们有一个注册表,用户可以在其中注册不同的实现
为此,我实现了一种策略模式,其中基于当前任务的每种合同类型都有一种策略。为了简单起见,假设任务是写,实际上要复杂得多
interface IWriteStrategy
{
public Write(IMaster thing);
}
class WriterA : IWriteStrategy
class WriterB : IWriteStrategy
etc
上述具体策略在我们的库中也从未“见过”,客户机必须注册自己的实现或我们的默认版本
设计缺陷??
我不喜欢现在需要的每一个策略中的演员
public classWriterA : IWriteStrategy
{
public void Write(IMaster thing)
{
if(thing is IA thingA)
//do some work
}
}
public classWriterB : IWriteStrategy
{
public void Write(IMaster thing)
{
if(thing is IB thingB)
//do some work
}
}
我们要做的是能够在IMaster
对象列表中循环并运行一些操作
foreach(var thing in Things)
{
var strategy = GetStrategy(thing.GetType()); //this gets the strategy object from our `registry` if one exists
strategy.Execute(thing);
}
上面的设计允许这一点,但似乎有一个缺陷,我不能为我的生活找到解决办法。我们必须转换到每个战略实施中的特定接口
我试过使用泛型,但似乎无法解决它
问题:
有什么更好的设计方法可以避免演员阵容,但仍然能够循环浏览IMaster
事物列表,并对它们一视同仁?还是说演员阵容是绝对必要的
我试图遵循一个可靠的设计,但觉得演员阵容正在搞乱这一点,因为实施策略的客户将不得不进行演员阵容,以便在Write
方法中实现任何功能
[编辑]
我已经更新了实现
IWriteStrategy
的类,也许使用Strategy模式并给出一个实现并执行它是合适的。让我举个例子
interface IMaster
{
void ExecuteMaster();
}
class MasterOne : IMaster
{
public void ExecuteMaster()
{
Console.WriteLine("Master One");
}
}
class MasterTwo : IMaster
{
public void ExecuteMaster()
{
Console.WriteLine("Master Two");
}
}
及
和要执行的代码:
static void Main(string[] args)
{
List<IWriteStrategy> writeStrategies = new List<IWriteStrategy>()
{
new WriterA(),
new WriterB()
};
List<IMaster> executes = new List<IMaster>()
{
new MasterOne(),
new MasterTwo()
};
for (int i = 0; i < writeStrategies.Count(); i++)
{
writeStrategies[i].Write(executes[i]);
}
}
static void Main(字符串[]args)
{
List writeStrategies=新列表()
{
新WriterA(),
新WriterB()
};
列表执行=新列表()
{
新MasterOne(),
新Master2()
};
对于(int i=0;i
关于这一点,您将在一个策略工厂方法中进行所有强制转换:
public interface IWriterStrategy
{
void Execute();
}
public class WriterA : IWriterStrategy
{
private readonly IA _thing;
public WriterA(IA thing)
{
_thing = thing;
}
public void Execute()
{
Console.WriteLine(_thing.PropOnA);
}
}
public class WriterB : IWriterStrategy
{
private readonly IB _thing;
public WriterB(IB thing)
{
_thing = thing;
}
public void Execute()
{
Console.WriteLine(_thing.PropOnB);
}
}
public static class WriterFactory
{
public static List<(Type Master, Type Writer)> RegisteredWriters = new List<(Type Master, Type Writer)>
{
(typeof(IA), typeof(WriterA)),
(typeof(IB), typeof(WriterB))
};
public static IWriterStrategy GetStrategy(IMaster thing)
{
(Type Master, Type Writer) writerTypeItem = RegisteredWriters.Find(x => x.Master.IsAssignableFrom(thing.GetType()));
if (writerTypeItem.Master != null)
{
return (IWriterStrategy)Activator.CreateInstance(writerTypeItem.Writer, thing);
}
throw new Exception("Strategy not found!");
}
}
public interface IMaster
{
//Some properties
}
public interface IA : IMaster
{
string PropOnA { get; set; }
}
public interface IB : IMaster
{
string PropOnB { get; set; }
}
public interface IC : IMaster
{
string PropOnC { get; set; }
}
public class ThingB : IB
{
public string PropOnB { get => "IB"; set => throw new NotImplementedException(); }
}
public class ThingA : IA
{
public string PropOnA { get => "IA"; set => throw new NotImplementedException(); }
}
public class ThingC : IC
{
public string PropOnC { get => "IC"; set => throw new NotImplementedException(); }
}
internal static class Program
{
private static void Main(string[] args)
{
var things = new List<IMaster> {
new ThingA(),
new ThingB()//,
//new ThingC()
};
foreach (var thing in things)
{
var strategy = WriterFactory.GetStrategy(thing); //this gets the strategy object from our `registry` if one exists
strategy.Execute();
}
}
}
公共接口IWriterStrategy
{
void Execute();
}
公共类编写:IWriterStrategy
{
私人只读信息系统;
公开写作(IA事务)
{
_事物=事物;
}
public void Execute()
{
控制台写入线(_thing.PropOnA);
}
}
公共类编写器B:IWriterStrategy
{
私有只读IB_东西;
公共作家B(IB事务)
{
_事物=事物;
}
public void Execute()
{
控制台写入线(_thing.PropOnB);
}
}
公共静态类WriterFactory
{
公共静态列表RegisteredWriters=新列表
{
(IA),(WriterA),,
(类型(IB),类型(WriterB))
};
公共静态IWriterStrategy GetStrategy(IMaster thing)
{
(Type Master,Type Writer)writerTypeItem=RegisteredWriters.Find(x=>x.Master.IsAssignableFrom(thing.GetType());
if(writerTypeItem.Master!=null)
{
return(IWriterStrategy)Activator.CreateInstance(writerTypeItem.Writer,thing);
}
抛出新异常(“未找到策略!”);
}
}
公共接口IMaster
{
//一些性质
}
公共接口IA:IMaster
{
字符串PropOnA{get;set;}
}
公共接口IB:IMaster
{
字符串PropOnB{get;set;}
}
公共接口IC:IMaster
{
字符串PropOnC{get;set;}
}
公共类事物B:IB
{
公共字符串PropOnB{get=>“IB”;set=>抛出新的NotImplementedException();}
}
公共类物品a:IA
{
公共字符串PropOnA{get=>“IA”;set=>抛出新的NotImplementedException();}
}
公共类内容C:IC
{
公共字符串PropOnC{get=>“IC”;set=>抛出新的NotImplementedException();}
}
内部静态类程序
{
私有静态void Main(字符串[]args)
{
var things=新列表{
新事物a(),
新事物b()/,
//新事物
};
foreach(事物中的事物)
{
var strategy=WriterFactory.GetStrategy(thing);//如果存在策略对象,则从'registry'获取该对象
strategy.Execute();
}
}
}
如果您很少添加新的IMaster
专门化,但经常添加新的操作或需要确保操作提供程序(如writer)需要支持所有专门化,则是完美的选择
否则,您基本上需要某种服务定位器和注册协议来将操作提供者/策略映射到IMaster
专业化
一种方法是定义通用接口,如IMasterWriter,其中T:IMaster
,然后可以像定义映射的IBWriter:IMasterWriter
那样实现
从这一点上讲,您只需要一种使用反射的机制来为给定类型的IMaster
找到特定的IMasterWriter
实现者,并决定如果缺少该实现者该怎么做。您可以尽早扫描程序集,以便在启动时检测缺少的实现,而不是在以后失败。谢谢您的帮助
public interface IWriterStrategy
{
void Execute();
}
public class WriterA : IWriterStrategy
{
private readonly IA _thing;
public WriterA(IA thing)
{
_thing = thing;
}
public void Execute()
{
Console.WriteLine(_thing.PropOnA);
}
}
public class WriterB : IWriterStrategy
{
private readonly IB _thing;
public WriterB(IB thing)
{
_thing = thing;
}
public void Execute()
{
Console.WriteLine(_thing.PropOnB);
}
}
public static class WriterFactory
{
public static List<(Type Master, Type Writer)> RegisteredWriters = new List<(Type Master, Type Writer)>
{
(typeof(IA), typeof(WriterA)),
(typeof(IB), typeof(WriterB))
};
public static IWriterStrategy GetStrategy(IMaster thing)
{
(Type Master, Type Writer) writerTypeItem = RegisteredWriters.Find(x => x.Master.IsAssignableFrom(thing.GetType()));
if (writerTypeItem.Master != null)
{
return (IWriterStrategy)Activator.CreateInstance(writerTypeItem.Writer, thing);
}
throw new Exception("Strategy not found!");
}
}
public interface IMaster
{
//Some properties
}
public interface IA : IMaster
{
string PropOnA { get; set; }
}
public interface IB : IMaster
{
string PropOnB { get; set; }
}
public interface IC : IMaster
{
string PropOnC { get; set; }
}
public class ThingB : IB
{
public string PropOnB { get => "IB"; set => throw new NotImplementedException(); }
}
public class ThingA : IA
{
public string PropOnA { get => "IA"; set => throw new NotImplementedException(); }
}
public class ThingC : IC
{
public string PropOnC { get => "IC"; set => throw new NotImplementedException(); }
}
internal static class Program
{
private static void Main(string[] args)
{
var things = new List<IMaster> {
new ThingA(),
new ThingB()//,
//new ThingC()
};
foreach (var thing in things)
{
var strategy = WriterFactory.GetStrategy(thing); //this gets the strategy object from our `registry` if one exists
strategy.Execute();
}
}
}