分享
 
 
 

.NET泛型技巧之打造可复用的抽象工厂

王朝c#·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

泛型不仅能用来做容器,还能够提供代码复用的手段。在泛型的参与下,许多设计就可能更精妙,更具扩展性。今天我就来演示一个利用泛型增强的抽象工厂模式。我们知道,抽象工厂(Abstract Factory)模式是将工厂和产品全部抽象化,一个抽象工厂生成一组抽象产品,而一个具体工厂则生成具体产品的一个特定组合。它能够维持这种相关对象组合的一致性,并使得用户不需要了解工厂和产品的具体实现。传统的Abstract Factory主要弱点是类型依赖性强,可复用性弱。一个抽象工厂通常是为一个特定需要而设计,通常不能被其他需要抽象工厂的场合使用。而且尽管抽象工厂可以将实际生产任务委派给特定类型的工厂,但这种委派是需要通过自己纯代码实现的,没能利用语言所提供的抽象特性。我们今天的任务就是编写一个不针对特定产品类型和数目的泛型抽象工厂,当你需要特定的抽象工厂时,可随时复用无需再定义专门的抽象工厂实现。

我们首先从只生成一个产品的工厂方法开始,以这作为抽象工厂的原料。很明显,可以设计这样一个接口作为工厂方法的模板:

public interface IFactory<T>

{

T Create();

}

这个工厂生产一个T类型的对象。当你实现此工厂时,应该让T为抽象产品的类型——即产品通用的基类。比如我们可以实现一个采用无参数构造函数来创建对象的OpNewFactory实现:

public class OpNewFactory<TAbstractProduct, TProduct> : IFactory<TAbstractProduct>

where TProduct : TAbstractProduct, new()

{

public TAbstractProduct Create()

{

return new TProduct();

}

}

从此例子可以看出,你应该仅实现抽象类型的IFactory接口,并生成具体类型。现在我们做完了单一产品的工厂方法模板,就要开始定义生产多个产品的抽象工厂接口了。.NET泛型支持按类型参数个数进行重载,就是说,我们可以定义生产一个、两个、三个……等多种数目的抽象工厂接口,而使用同一个名字。(汗吧,这就是所谓支持“任意数目”的手法)这里免不了要拷贝代码,不过别担心,纯拷贝而已,使用的时候可是非常舒心的哦。我们以生产两种产品类型的抽象工厂为例介绍。能不能定义成这样呢?

public interface IAbstractFactory<T1, T2>

{

T1 Create();

T2 Create(); //编译错误!!!

}

哦不!方法不能以返回类型区分重载,只能靠参数类型重载。然而这里我们显然不能用T1和T2作为参数,因为这些方法就是为了生产T1和T2准备的,怎么能接受它们作为参数呢?难道要命名为Create1和Create2吗?这很难接受,我们希望生产方法能够体现产品的类型,怎么能叫1和2呢。为了解决这个问题,我们引入了TypeToken<T>类型,它的定义如下:

public sealed class TypeToken<T>

{

static private TypeToken<T> instanceValue = new TypeToken<T>();

static public TypeToken<T> Instance

{

get { return instanceValue; }

}

private TypeToken() { }

}

这个类没有成员,并且每个类型实参只能创建一个实例,因此代价极小。但就是这小小的实例上带有其类型实参的类型信息,因此可以作为判断函数重载的依据。我们用TypeToken<T>作为区分生产函数重载的依据,实现如下:

public interface IAbstractFactory<T1, T2>

{

T1 Create(TypeToken<T1> token);

T2 Create(TypeToken<T2> token);

}

现在我们针对抽象工厂实现具体工厂。具体工厂就是利用生产每种产品的单一工厂来组合实现。因此你只要有每种类型的单一工厂就可以直接组合生成抽象工厂,而无需定义一个类来做这件事。注意,对每种数目的抽象工厂接口都需要对应生成一个具体工厂的实现,这里我仅针对生成两个产品的演示:

public class ConcreteFactory<T1, T2> : IAbstractFactory<T1, T2>

{

private IFactory<T1> factory1;

private IFactory<T2> factory2;

public ConcreteFactory(IFactory<T1> f1, IFactory<T2> f2)

{

factory1 = f1;

factory2 = f2;

}

public T1 Create(TypeToken<T1> token)

{

return factory1.Create();

}

public T2 Create(TypeToken<T2> token)

{

return factory2.Create();

}

}

public static class ConcretFactory

{

public static ConcreteFactory<T1, T2> NewFactory<T1, T2>(IFactory<T1> f1, IFactory<T2> f2)

{

return new ConcreteFactory<T1, T2>(f1, f2);

}

}

注意,我又声明了一个没有类型参数的ConcretFactory类,用一个静态方法来生成泛型ConcretFactory的实例,这是因为使用泛型方法可以推测类型参数,使得我们可以不必输入尖括号或Of语句,而泛型类则没有这个功能。现在大功告成!我们用一个例子来演示这个泛型抽象工厂的工作情况。现在假设我们需要一个生产PC的抽象工厂,需要生产两种抽象产品:处理器和内存。处理器和内存的抽象和具体实现如下:

Processor 和 Ram

public abstract class Processor

{

public abstract string Model { get; }

}

public abstract class Ram

{

public abstract int Frequency { get;}

}

public class PentiumProcessor : Processor

{

public override string Model

{

get { return "Pentium Extreme Edition 955"; }

}

}

public class AthlonProcessor : Processor

{

public override string Model

{

get { return "Athlon 64 X2 FX-60"; }

}

}

public class DDRRam : Ram

{

public override int Frequency

{

get { return 400; }

}

}

public class DDR2Ram : Ram

{

public override int Frequency

{

get { return 533; }

}

}

下面的代码演示了如何随心所欲生成想要的抽象工厂接口以及快速从现有单一产品工厂组合成特定的具体工厂实现。

class Program

{

static IAbstractFactory<Processor, Ram> ComputerFactory(string type)

{

if (type == "Intel")

{

return ConcretFactory.NewFactory( new OpNewFactory<Processor, PentiumProcessor>(),

new OpNewFactory<Ram, DDR2Ram>());

}

else if (type == "AMD")

{

return ConcretFactory.NewFactory( new OpNewFactory<Processor, AthlonProcessor>(),

new OpNewFactory<Ram, DDRRam>());

}

//unknown type

return null;

}

static void Main(string[] args)

{

//Yield a computer of Intel

IAbstractFactory<Processor, Ram> factory1 = ComputerFactory("Intel");

Ram ram1 = factory1.Create(TypeToken<Ram>.Instance);

Processor cup1 = factory1.Create(TypeToken<Processor>.Instance);

Console.WriteLine("An Intel Computer");

Console.WriteLine("CPU Model: {0}", cup1.Model);

Console.WriteLine("Memory Frequency: {0} MHz", ram1.Frequency);

Console.WriteLine();

//Yield a computer of AMD

IAbstractFactory<Processor, Ram> factory2 = ComputerFactory("AMD");

Ram ram2 = factory2.Create(TypeToken<Ram>.Instance);

Processor cup2 = factory2.Create(TypeToken<Processor>.Instance);

Console.WriteLine("An AMD Computer");

Console.WriteLine("CPU Model: {0}", cup2.Model);

Console.WriteLine("Memory Frequency: {0} MHz", ram2.Frequency);

}

}

总结:

我们用泛型技术成功地增强了原本重用性较低的抽象工厂,演示了泛型在提高抽象性和代码重用方面卓越的价值。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有