使用泛型实例化对象是否是一个好主意?
假设我有一个Animal类和一些子类(Cat,Dog等):
abstract class Animal
{
public abstract void MakeSound();
}
class Cat : Animal
{
public override void MakeSound()
{
Console.Write("Mew mew");
}
}
class Dog : Animal
{
public override void MakeSound()
{
Console.Write("Woof woof");
}
}
static class AnimalFactory
{
public static T Create<T>() where T : Animal, new()
{
return new T();
}
}
然后在我的代码中,我会像这样使用AnimalFactory:
class Program
{
static void Main(string[] args)
{
Dog d = AnimalFactory.Create<Dog>();
d.MakeSound();
}
}
答案 0 :(得分:4)
取决于你想用它做什么。你给出的例子并没有那么有用,因为它所做的只是调用new(),这也是你可以在你的代码中做的事情。如果要在对象创建过程中放置必须在要创建的对象之外的某个位置运行逻辑,而且远离实例化对象的代码,则工厂更有用。
从这个角度来看,这取决于你想在工厂中运行什么逻辑,以及该逻辑是否也可以使用与工厂相同的通用约束来写入。如果没有,您可能需要一个名为Abstract factory的模式,该模式使用一般工厂在幕后为该类型创建正确的特定工厂以创建手头的对象。
答案 1 :(得分:3)
是的,非泛型类中的工厂方法通常很有用。特别是,通用方法可以对它们应用类型推断,而通用类型则不能。
我有时也有两层工厂 - 对于具有2个类型参数的泛型类型,我可能有:
class Foo
{
static Foo<TKey, TValue> Create<TKey, TValue>(TKey key, TValue value)
{...}
}
class Foo<TKey>
{
static Foo<TKey, TValue> Create<TValue>(TValue value)
{...}
}
class Foo<TKey, TValue>
{
}
这允许:
Foo.Create(x, y);
Foo<string>.Create(y);
new Foo<string, int>(x, y);
我有一个blog entry,其中包含更多示例和推理。
答案 2 :(得分:1)
由此产生的一个更烦人的事情,可能有一种解决方法,就是你使用无参数构造函数。据我所知,你不能这样做:
public class Factory
{
public static T Create<T>() where T : ParentClass, new(String)
{
}
}
或者这个
public class Factory
{
public static T Create<T>() where T : ParentClass
{
T child = new T("hi")
}
}
甚至更有趣:
public class Factory
{
public static T Create<T>() where T : ParentClass, new()
{
T child;
child = new T();
if (child is ChildClass)
{
child = new ChildClass("hi");
}
return child;
}
}
这可能会限制您使用某些课程设计。如果您不想只调用默认构造函数,则可能会出现问题。
除非有人找到解决这个问题的方法,否则这就行了。
我知道我在Activator.CreateInstance()中遇到了这个问题,因为实际上所有这一切都是调用无参数构造函数。
答案 3 :(得分:1)
我建议将工厂问题与构造函数关注点分开。这允许不同的实例化策略:
public interface IFactory<T>
{
T Create();
}
public class DefaultConstructorFactory<T> : IFactory<T> where T : new()
{
public T Create()
{
return new T();
}
}
public class ActivatorFactory<T> : IFactory<T>
{
public T Create()
{
return Activator.CreateInstance<T>();
}
}
public class AnimalTamer<TAnimal> where TAnimal : Animal
{
IFactory<TAnimal> _animalFactory;
public AnimalTamer(IFactory<TAnimal> animalFactory)
{
if(animalFactory == null)
{
throw new ArgumentNullException("animalFactory");
}
_animalFactory= animalFactory;
}
public void PutOnShow()
{
var animal = _animalFactory.Create();
animal.MakeSound();
}
}
class Program
{
static void Main(string[] args)
{
var tamer = new AnimalTamer<Tiger>(new DefaultConstructorFactory<Tiger>());
tamer.PutOnShow();
}
}
答案 4 :(得分:1)
通过使用打开/关闭泛型和函数可以使它更加动态,直到运行时才会知道或者很少知道。好像你已经很好地掌握了仿制药,所以要坚持下去。
答案 5 :(得分:0)
使用泛型构造函数称为抽象工厂模式。
它很好,但只有当你使用它时,在这个例子中你至少有一些默认值。
static class AnimalFactory
{
public static Animal Create<T>() where T : Animal
{
return Create<T>("blue");
}
public static Animal Create<T>(string colour) where T : Animal, new()
{
return new T() {Colour = colour};
}
}
答案 6 :(得分:0)
拥有工厂是个好主意 使用泛型实例化的类 对象
对于你描述的情况,不是不是。你只是为了使用一个模式而使用一个模式,从这个例子来看,它只会不必要地复杂化。
现在,如果您的应用程序有多个对象实现某个接口,并且您根据配置文件加载其中一个对象,那么是的,使用工厂创建该对象是有意义的。
这个问题的泛型部分实际上会出现在工厂实现中。我没有支持代码,但这是我设想调用代码的方式:
Factory<IAwesome> awesomeFactory = new Factory<IAwesome>();
IAwesome awesomeObject = awesomeFactory.Load(configValue);
答案 7 :(得分:0)
是肯定的。创作设计模式(http://en.wikipedia.org)适用于泛型。而且泛型可能有点复杂(http://www.artima.com/intv/genericsP.html),因此可以隐藏某种工厂中的任何构造复杂性,以使客户更容易。