具有通用接口的工厂方法
Factory Method with Generic Interface
我有两种不同类型的项目:图片和视频。为了管理它们,我创建了一个接口和两个实现它的 classes
public interface Item{
}
public class ItemPicture: Item{
}
public class ItemVideo: Item {
}
现在我有一些 classes 来管理那些继承自管理器界面的项目
public interface ItemManager<T>{
IList<T> FGetByGroup(string idgroup);
}
public class ItemManagerPictures : IItemManager<ItemPicture>{
public IList<ItemFoto> FGetByGroup(string idgroup){
...
}
}
public class ItemManagerVideos: IItemManager<ItemVideo>{
public IList<ItemVideo> FGetByGroup(string idgroup){
...
}
}
为了有一个创建适当对象的工厂方法,我创建了这个 class
public class ItemManagerCreator
{
public static IItemManager<Item> MakeItemManager(string type)
{
IItemManager<Item> objMgr = null;
switch (type)
{
case "Picture":
objMgr = (IItemManager<Item>)new ItemManagerPictures();
break;
case "Video":
objMgr = (IItemManager<Item>)new ItemManagerVideos();
break;
default:
break;
}
return objMgr ;
}
}
从控制器我想这样做
var type="Picture";
IItemManager<Item> itemMgr = ItemManagerCreator.MakeItemManager(type);
var itemList = itemMgr.FGetByGroup(string idgroup);
但是我得到这个转换错误
Can't convert from type '...ItemManagerPictures' to type '...IItemManager`1[...Item]'.
这让我觉得我做错了什么,但是转了1000次之后,我认为问题出在工厂方法和泛型上,它们设计得不好。
我是设计模式的新手,也许我没有应用正确的模式。
提前致谢
它不能按原样工作,因为 ItemManagerPictures
和 ItemManagerVideos
确实不能转换为 IItemManager<Item>
,检查 covariance and contravariance 看看为什么。
在这种情况下,因为您实际上不需要将 IList
用作 FGetByGroup
的 return 类型(如评论中所示),您可以使用一些在通用类型 T
中协变的接口(例如 IEnumerable<T>
或 IReadOnlyList<T>
),然后将您的类型 T
也声明为 covariant:
public interface IItemManager<out T>{
IReadOnlyList<T> FGetByGroup(string idgroup);
}
public class ItemManagerPictures : IItemManager<ItemPicture>{
public IReadOnlyList<ItemPicture> FGetByGroup(string idgroup) {
return null;
}
}
现在,ItemManagerPictures
可分配给 IItemManager<Item>
,因此您的代码将毫无例外地工作。
从你的代码中你似乎事先知道你想要什么类型的 ItemManager,所以你可以这样做:
public class ItemManagerCreator
{
public static IItemManager<T> MakeItemManager<T>() where T : Item
{
if (typeof(T) == typeof(ItemPicture))
{
return (IItemManager<T>)new ItemManagerPictures();
}
if (typeof(T) == typeof(ItemVideo))
{
return (IItemManager<T>)new ItemManagerVideos();
}
throw new InvalidOperationException();
}
}
并供使用:
string groupId = string.Empty;
dynamic itemManager = null;
我想要一张IItemManager
的图片
itemManager = ItemManagerCreator.MakeItemManager<ItemPicture>();
IList<ItemPicture> pictures = itemManager.FGetByGroup(groupId);
然后我想要一个 IItemManager
的视频
itemManager = ItemManagerCreator.MakeItemManager<ItemVideo>();
IList<ItemVideo> videos = itemManager.FGetByGroup(groupId);
我有两种不同类型的项目:图片和视频。为了管理它们,我创建了一个接口和两个实现它的 classes
public interface Item{
}
public class ItemPicture: Item{
}
public class ItemVideo: Item {
}
现在我有一些 classes 来管理那些继承自管理器界面的项目
public interface ItemManager<T>{
IList<T> FGetByGroup(string idgroup);
}
public class ItemManagerPictures : IItemManager<ItemPicture>{
public IList<ItemFoto> FGetByGroup(string idgroup){
...
}
}
public class ItemManagerVideos: IItemManager<ItemVideo>{
public IList<ItemVideo> FGetByGroup(string idgroup){
...
}
}
为了有一个创建适当对象的工厂方法,我创建了这个 class
public class ItemManagerCreator
{
public static IItemManager<Item> MakeItemManager(string type)
{
IItemManager<Item> objMgr = null;
switch (type)
{
case "Picture":
objMgr = (IItemManager<Item>)new ItemManagerPictures();
break;
case "Video":
objMgr = (IItemManager<Item>)new ItemManagerVideos();
break;
default:
break;
}
return objMgr ;
}
}
从控制器我想这样做
var type="Picture";
IItemManager<Item> itemMgr = ItemManagerCreator.MakeItemManager(type);
var itemList = itemMgr.FGetByGroup(string idgroup);
但是我得到这个转换错误
Can't convert from type '...ItemManagerPictures' to type '...IItemManager`1[...Item]'.
这让我觉得我做错了什么,但是转了1000次之后,我认为问题出在工厂方法和泛型上,它们设计得不好。
我是设计模式的新手,也许我没有应用正确的模式。
提前致谢
它不能按原样工作,因为 ItemManagerPictures
和 ItemManagerVideos
确实不能转换为 IItemManager<Item>
,检查 covariance and contravariance 看看为什么。
在这种情况下,因为您实际上不需要将 IList
用作 FGetByGroup
的 return 类型(如评论中所示),您可以使用一些在通用类型 T
中协变的接口(例如 IEnumerable<T>
或 IReadOnlyList<T>
),然后将您的类型 T
也声明为 covariant:
public interface IItemManager<out T>{
IReadOnlyList<T> FGetByGroup(string idgroup);
}
public class ItemManagerPictures : IItemManager<ItemPicture>{
public IReadOnlyList<ItemPicture> FGetByGroup(string idgroup) {
return null;
}
}
现在,ItemManagerPictures
可分配给 IItemManager<Item>
,因此您的代码将毫无例外地工作。
从你的代码中你似乎事先知道你想要什么类型的 ItemManager,所以你可以这样做:
public class ItemManagerCreator
{
public static IItemManager<T> MakeItemManager<T>() where T : Item
{
if (typeof(T) == typeof(ItemPicture))
{
return (IItemManager<T>)new ItemManagerPictures();
}
if (typeof(T) == typeof(ItemVideo))
{
return (IItemManager<T>)new ItemManagerVideos();
}
throw new InvalidOperationException();
}
}
并供使用:
string groupId = string.Empty;
dynamic itemManager = null;
我想要一张IItemManager
的图片
itemManager = ItemManagerCreator.MakeItemManager<ItemPicture>();
IList<ItemPicture> pictures = itemManager.FGetByGroup(groupId);
然后我想要一个 IItemManager
的视频
itemManager = ItemManagerCreator.MakeItemManager<ItemVideo>();
IList<ItemVideo> videos = itemManager.FGetByGroup(groupId);