现在的位置: 首页 > 综合 > 正文

设计模式–工厂方法模式

2012年08月25日 ⁄ 综合 ⁄ 共 2781字 ⁄ 字号 评论关闭

工厂方法模式:

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

结构图:

image

解决的问题:

在软件系统中,我们会遇到这样一个问题,我们通过某种渠道实现了某个操作后,由于需求变化,或者其他一些原因,导致这个操作需要通过另外的渠道实现,从而导致我们不得不修改这个实现方法.如何封装这样一个易变的地方.工厂方法模式不能解决修改的问题,因为需求带来的变化,导致我们可能会对代码进行改变,我们进行封装的目的是为了减少改变,即:原来修改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 里添加新的方法,以适应新需求的变化,这就违反了"开放封闭原则"(对扩展开放,对修改封闭),我们仔细观察这些方法,无论是采用火车、汽车、飞机、管道运输石油,都可以抽象出一个方法:运输石油。于是,我们的设计如下:

image 

此时,如果我们在添加新的运输方式时,只需要继承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都要被修改才可以.于是工厂方法模式出现了:

image

代码:

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即可.

抱歉!评论已关闭.