您的位置:首页 > 其它

设计模式--工厂方法模式

2009-04-28 15:35 162 查看
工厂方法模式:

定义了一个创建对象的接口,但是这个类不实际生成对象的实例,而是由其子类来进行实例化.工厂方法模式让类的实例化推迟到子类.

结构图:





解决的问题:

在软件系统中,我们会遇到这样一个问题,我们通过某种渠道实现了某个操作后,由于需求变化,或者其他一些原因,导致这个操作需要通过另外的渠道实现,从而导致我们不得不修改这个实现方法.如何封装这样一个易变的地方.工厂方法模式不能解决修改的问题,因为需求带来的变化,导致我们可能会对代码进行改变,我们进行封装的目的是为了减少改变,即:原来修改10处,现在修改一处即可.

使用此模式的前提是:在使用这个类的一些范围内,所有的对象都能抽象出共同的方法。

举个例子:

显示生活中的运输石油.我们决定使用火车运输,于是我们建立一个类,实现了以火车运输石油的方法.并且在大量的城市里都采用这种方式来运输.有一天,需求变化了,用火车运输石油导致城市严重污染,并且安全性不高,要求采用管道运输.于是我们就需要修改最初始建立的一个类,建立一个方法:输油管道().并且修改大量引用到用火车运油的地方.

刚开始设计的类:

public class CarryOil
{
public string CarryByTrain()
{
return "Use Train";
}
}
修改后:

public class CarryOil
{
public string CarryByTrain()
{
return "Use Train";
}

public string CarryByPiping()
{
return "Use Piping";
}
}


这样,如果下次要求空运,汽车运,那么该怎么处理呢?继续在CarryOil 里添加新的方法,以适应新需求的变化,这就违反了"开放封闭原则"(对扩展开放,对修改封闭),我们仔细观察这些方法,无论是采用火车、汽车、飞机、管道运输石油,都可以抽象出一个方法:运输石油。于是,我们的设计如下:





此时,如果我们在添加新的运输方式时,只需要继承CarryOil类,实现Carry方法即可.此时,我们也无需再去关心关心其他两种运输方式是如何实现的.符合了面向对象设计中的单一职责原则,同时也很好的应用了"开放封闭原则".客户端调用时,代码如下:

protected void Page_Load(object sender, EventArgs e)
{
CarryOil c = new CarryOilWithTrain();
Display(c);
}

void Display(CarryOil c)
{
Response.Write("方式:" + c.Carry() + "<hr/>");
}


到这里,似乎设计没有问题,如果采用管道运输的话,直接改为CarryOilWithPiping即可.但是如果是页面上多处调用了上面的代码,并且都需要修改为CarryOilWithPiping时该怎么办呢?

例如:

protected void Page_Load(object sender, EventArgs e)
{
CarryOil c1 = new CarryOilWithTrain();
Display(c1);

CarryOil c2 = new CarryOilWithTrain();
Display(c2);

CarryOil c3 = new CarryOilWithTrain();
Display(c3);
}

void Display(CarryOil c)
{
Response.Write("方式:" + c.Carry() + "<hr/>");
}


此时,如果改为使用管道运输,则3个CarryOilWithTrain都要被修改才可以.于是工厂方法模式出现了:





代码:

public interface ITransport
{
CarryOil GetTraffic();
}

public class TransportWithTrain : ITransport
{

public CarryOil GetTraffic()
{
return new CarryOilWithTrain();
}
}

public class TransportWithPiping : ITransport
{

public CarryOil GetTraffic()
{
return new CarryOilWithPiping();
}
}
此时,页面调用时,如下方式调用:
protected void Page_Load(object sender, EventArgs e)
{
ITransport factory = new TransportWithTrain();

CarryOil c1 = factory.GetTraffic();
Display(c1);

CarryOil c2 = factory.GetTraffic();
Display(c2);

CarryOil c3 = factory.GetTraffic();
Display(c3);
}

void Display(CarryOil c)
{
Response.Write("方式:" + c.Carry() + "<hr/>");
}
此时,如果需要修改为使用管道的话,只需要修改TransportWithTrain为TransportWithPiping即可,实现了一处修改,而不是像上面三处修改.
而且在页面调用时,也没有使用到具体的类(这里指具体的产品类).此时是一个页面,多处调用了TransportWithTrain这个类,若是多个页面调用了这个类,该如何处理呢?

此时可以将ITransport factory = new TransportWithTrain(); 放在一个类里,如下:
public class CreateFactory
{
public CreateFactory()
{
//
//TODO: 在此处添加构造函数逻辑
//
}

public ITransport CreateTransportFactory()
{
ITransport tran = new TransportWithTrain();
return tran;
}
}
页面调用时:
protected void Page_Load(object sender, EventArgs e)
{
CreateFactory cf = new CreateFactory();
ITransport factory = cf.CreateTransportFactory();

CarryOil c = factory.GetTraffic();
Display(c);
}

void Display(CarryOil c)
{
Response.Write("方式:" + c.Carry() + "<hr/>");
}


多少个页面调用这样的语句都可以,如果需要修改,使用管道时,只需要将CreateFactory类中CreateTransportFactory中的TransportWithTrain换成TransportWithPiping即可.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: