第2篇 设计模式的实现与使用
第六章 简单工厂
面向接口编程要求针对接口,而不是具体的实现。有一个问题是,尽管编程是面向接口,但执行时的操作需要实例化后的对象,而实例化必须要针对具体的类。若直接实例化,则破坏了面向接口的编程原则。解决的方法就是通过一个专门实例化的类来获得具体的对象,通常将这个类称为“工厂”,将与实例化相关的模式称为“创建型模式”。
1.意图
简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类。
2.使用场合
简单工厂实例化的类具有相同的接口,类类有限并且基本不需要扩展。
3..NET实现
通常简单工厂不需要实例化,而是采用静态方法。
·抽象类与接口优劣性的讨论:
如果需要被实例化的子类有大量相同代码,可考虑采用抽象类,可以减少代码的重复。然而这样做的缺点是扩展性不好,子类之间存在潜在的耦合性。因此通常可考虑采用接口代替抽象类。
·代码框架
//
交通工具是一个必须继承的基类
public abstract class Vehicle
{
protected string m_TypeName;
public string TypeName
{
get
{
return m_TypeName;
}
set
{
m_TypeName = Value;
}
}
public abstract string Go()
}
// 汽车是交通工具的子类
public class Car:Vehicle
{
public Car()
{
m_TypeName = " 汽车 " ;
}
public override string Go()
{
return " 汽车在公路上开 " ;
}
}
// 火车是交通工具的子类
public class Train:Vehicle
{
public Car()
{
m_TypeName = " 火车 " ;
}
public override string Go()
{
return " 火车在铁轨上开 " ;
}
}
// 船是交通工具的子类
public class Boat:Vehicle
{
public Car()
{
m_TypeName = " 船 " ;
}
public override string Go()
{
return " 船在水上走 " ;
}
}
public class CreateAVehicle
{
// 将创建方法定义为静态
public static Vehicle CreateAVehicle( string typeid)
{
Vehicle v;
// 根据参数确定需要创建的对象
switch (typeid.ToLower())
{
case " car " :
v = new Car();
break ;
case " train " :
v = new Train();
break ;
case " boat " :
v = new Boat();
break ;
}
return v;
}
}
4.应用
public abstract class Vehicle
{
protected string m_TypeName;
public string TypeName
{
get
{
return m_TypeName;
}
set
{
m_TypeName = Value;
}
}
public abstract string Go()
}
// 汽车是交通工具的子类
public class Car:Vehicle
{
public Car()
{
m_TypeName = " 汽车 " ;
}
public override string Go()
{
return " 汽车在公路上开 " ;
}
}
// 火车是交通工具的子类
public class Train:Vehicle
{
public Car()
{
m_TypeName = " 火车 " ;
}
public override string Go()
{
return " 火车在铁轨上开 " ;
}
}
// 船是交通工具的子类
public class Boat:Vehicle
{
public Car()
{
m_TypeName = " 船 " ;
}
public override string Go()
{
return " 船在水上走 " ;
}
}
public class CreateAVehicle
{
// 将创建方法定义为静态
public static Vehicle CreateAVehicle( string typeid)
{
Vehicle v;
// 根据参数确定需要创建的对象
switch (typeid.ToLower())
{
case " car " :
v = new Car();
break ;
case " train " :
v = new Train();
break ;
case " boat " :
v = new Boat();
break ;
}
return v;
}
}
对于数据库类型的不同,可将其统一封装于一个简单工厂中,方便使用及日后的维护。
对于程序的配置信息的保存位置(如:配置文件,注册表,数据库等),也可用简单工厂封存装。
第七章 工厂方法模式
工厂方法是粒度很小的设计模式,因为模式的表现只是一个抽象的方法。工厂方法经常用于创建与某个类相关的类的实例。
1.意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到子类,这个接口所指的是一个抽象方法。该方法说明需要创建一个对象,但并不给出具体的创建方法和创建什么类型的对象。
·代码:
using
System;
namespace CSharpCreator
{
public abstract class Creator
{
public abstract production FactoryMethod();
}
public class ConcreteCreator:Creator
{
public override production FactoryMethod()
{
return new ConcreteProduction();
}
}
}
2.使用场合
namespace CSharpCreator
{
public abstract class Creator
{
public abstract production FactoryMethod();
}
public class ConcreteCreator:Creator
{
public override production FactoryMethod()
{
return new ConcreteProduction();
}
}
}
当一个类不知道它所必须创建对象的类或一个类希望由子类来指定它所创建的对象时。
3.应用——获得多媒体播放对象
希望同一个架构既可以采用RealPlay播放器,也可以用MSMedia Player播放器。
·代码框架(省略了系统自动生成的代码)
public
abstract
class
BasePlayForm:System.Windows.Forms.Form
// 播放器声明为符合AudioPlayer接口
protected AudioPlayer mmply;
// 工厂方法,在子类中定义具体的播放器
protected abstract AudioPlayer GetMP();
// 打开媒体文件
private void mnOpen_Click( object sender, ImageClickEventArgs e)
{
if ( this .OpenFileDialog1.ShowDialog == DialogResult.OK)
{
mmply = GetMP();
mmply.Source = this .OpenFileDialog.FileName;
}
}
// 播放
private void mnPlay_Click( object sender, ImageClickEventArgs e)
{
mmply.DoPlay();
}
// 暂停
private void mnPause_Click( object sender, ImageClickEventArgs e)
{
mmply.DoPause();
}
// 停止
private void mnStop_Click( object sender, ImageClickEventArgs e)
{
mmply.DoStop();
}
以下是采用RealPlay和MS Media Player播放器的代码(分别继承自BasePlayForm类)
// 播放器声明为符合AudioPlayer接口
protected AudioPlayer mmply;
// 工厂方法,在子类中定义具体的播放器
protected abstract AudioPlayer GetMP();
// 打开媒体文件
private void mnOpen_Click( object sender, ImageClickEventArgs e)
{
if ( this .OpenFileDialog1.ShowDialog == DialogResult.OK)
{
mmply = GetMP();
mmply.Source = this .OpenFileDialog.FileName;
}
}
// 播放
private void mnPlay_Click( object sender, ImageClickEventArgs e)
{
mmply.DoPlay();
}
// 暂停
private void mnPause_Click( object sender, ImageClickEventArgs e)
{
mmply.DoPause();
}
// 停止
private void mnStop_Click( object sender, ImageClickEventArgs e)
{
mmply.DoStop();
}
public
class
PlayMedia:BasePlayForm
{
protected override AudioPlayer GetMP()
{
return new MediaPlayer();
}
}
public class PlayReal:BasePlayForm
{
protected override AudioPlayer GetMP()
{
RealAudioPlayClass c = new RealAudioPlayerClass( this );
return c;
}
}
{
protected override AudioPlayer GetMP()
{
return new MediaPlayer();
}
}
public class PlayReal:BasePlayForm
{
protected override AudioPlayer GetMP()
{
RealAudioPlayClass c = new RealAudioPlayerClass( this );
return c;
}
}
·工厂方法使类中的代码不依赖于它必须创建的类,代码只要知道它需要创建的类的接口。工厂方法的缺点是新增加一个需要创建的类,就需要增加一个相应的子类。