设计模式--简单工厂、工厂方法、抽象工厂方法

定义:

工厂方法:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个.工厂方法让类把实例化推迟到子类

抽象工厂模式:提供一个接口,用于创建相关或依赖具体对象的家族,而不需要明确指定具体类.

要点:

    1. 所有的工厂都是用来封装对象的创建
    2. 简单工厂,虽然不是真正的设计模式,但仍不失位一个简单的办法,可以将客户程序从具体类中解耦出来
    3. 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
    4. 抽象工厂使用对象组合:对象的实现被实现在工厂接口所暴露出来的方法
    5. 所有工厂模式都通过减少应用程序和具体类之间的依赖进行松耦合
    6. 工厂方法允许类将实例化延迟到子类进行
    7. 抽象工厂创建相关的对象家族,而不需要依赖他们的具体类
    8. 依赖导致原则,指导我们避免依赖具体类型,而要尽量依赖抽象
    9. 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体编程

个人理解:

当我们在一个类中,使用另一个时,往往是通过new的方式new出来的这个类的实例,然后再进行使用.这其中即使我们使用的类有抽象类或接口,但仍免不了出现 absclass c = new subclass()这样一种情况.于是,就出现了耦合;实际上,我们要如何才能处理这样一个问题,实现解耦呢?

想想我们在实际生活中接触的计算机,这个例子也许可以说明一点问题.计算机有主板,硬盘,光驱,内存,显示器,鼠标,键盘等几个零部件构成.我们在使用时是将硬盘、光驱、内存、显示器、鼠标、键盘插在了主板上,就可以使用了。而不是让主板new出一个硬盘,然后再使用硬盘,也不是让主板new出一个光驱,然后再使用光驱.而是让外界提供一个new好的硬盘,然后插给主板的硬盘接口上即可.

 如下:

public class MainBoard
{
    private HardDisk1 hd;
    public MainBoard()
    {
        //
        //TODO: 在此处添加构造函数逻辑
        //
    }

    public MainBoard(HardDisk1 hd)
    {
        this.hd = hd;
    }

    public void ReadHD()
    {
        hd.Read();
    }
}

/// <summary>
/// HardDisk1为某一个具体品牌的硬盘
/// </summary>
public class HardDisk1
{
    public void Read()
    {
        HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>");
    }
}

----------------------------------------

    protected void Page_Load(object sender, EventArgs e)
    {
        HardDisk1 hd = new HardDisk1();
        MainBoard mainboard = new MainBoard(hd);
        mainboard.ReadHD();
    }
但是,此时还是没有解耦,主板是面向的HardDisk1来运行的.如何面向其他的硬盘呢.此时可以使用抽象类和简单工厂,如下:
public class MainBoard
{
    private HardDisk hd;
    public MainBoard()
    {
        //
        //TODO: 在此处添加构造函数逻辑
        //
    }

    public MainBoard(HardDisk hd)
    {
        this.hd = hd;
    }

    public HardDisk Hd
    {
        get { return this.hd; }
        set { this.hd = value; }
    }

    public void ReadHD()
    {
        hd.Read();
    }
}

public abstract class HardDisk
{
    public abstract void Read();
}

/// <summary>
/// HardDisk1为某一个具体品牌的硬盘
/// </summary>
public class HardDisk1 : HardDisk
{
    public override void Read()
    {
        HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>");
    }
}

/// <summary>
/// HardDisk1为某一个具体品牌的硬盘
/// </summary>
public class HardDisk2 : HardDisk
{
    public override void Read()
    {
        HttpContext.Current.Response.Write("HardDisk2 is reading.<br/>");
    }
}

public class HardDiskSimpleFactory
{
    public HardDisk CreateHardDisk(string type)
    {
        if (type.ToLower() == "harddisk1")
        {
            return new HardDisk1();
        }
        else
        {
            return new HardDisk2();
        }
    }
}

------------------------------------------------------

    protected void Page_Load(object sender, EventArgs e)
    {
        HardDiskSimpleFactory hdsf = new HardDiskSimpleFactory();
        HardDisk hd1 = hdsf.CreateHardDisk("harddisk1");
        MainBoard mainboard = new MainBoard(hd1);
        mainboard.ReadHD();

        HardDisk hd2 = hdsf.CreateHardDisk("harddisk2");
        mainboard.Hd = hd2;
        mainboard.ReadHD();
    }

 

查看此时,主板和硬盘是否已经解耦,主板是不是没有new硬盘,也没有针对具体的硬盘进行读操作?此时我们使用的是简单工厂,简单工厂不是一个模式,而是我们在使用中养成的一个习惯.

此时再看,主板和硬盘是已经解耦了,但是看看HardDiskSimpleFactory类是否违背了开放-封闭原则.

开放-封闭原则是对扩展开放,对修改关闭,此时,如果我们新增加了一个硬盘类型HardDisk3的话,是不是又要对HardDiskSimpleFactory类进行修改呢?如果能避免再扩展类的同时,又对这个类进行修改?此时我们就要使用工厂方法模式.

代码修改如下:

public abstract class HardDiskFactory
{
    public abstract HardDisk CreateHardDisk();
}

public class HardDisk1Factory : HardDiskFactory
{
    public override HardDisk CreateHardDisk()
    {
        return new HardDisk1();
    }
}

public class HardDisk2Factory : HardDiskFactory
{
    public override HardDisk CreateHardDisk()
    {
        return new HardDisk2();
    }
}

------------------------------------------------

    protected void Page_Load(object sender, EventArgs e)
    {
        HardDiskFactory hdsf1 = new HardDisk1Factory();
        HardDisk hd1 = hdsf1.CreateHardDisk();
        MainBoard mainboard = new MainBoard(hd1);
        mainboard.ReadHD();

        HardDiskFactory hdsf2 = new HardDisk2Factory();
        HardDisk hd2 = hdsf2.CreateHardDisk();
        mainboard.Hd = hd2;
        mainboard.ReadHD();
    }

此时,已经基本不再违背开放-封闭原则,如果我们现在有了新的硬盘类型HardDisk3,那我们该怎么办呢?

//新增一个硬盘类型HardDisk3
public class HardDisk3 : HardDisk
{
    public override void Read()
    {
        HttpContext.Current.Response.Write("HardDisk3 is reading.<br/>");
    }
}

//新增一个工厂HardDisk3Factory
public class HardDisk3Factory : HardDiskFactory
{
    public override HardDisk CreateHardDisk()
    {
        return new HardDisk3();
    }
}

-------------------------------------------------

    protected void Page_Load(object sender, EventArgs e)
    {
        HardDiskFactory hdsf1 = new HardDisk1Factory();
        HardDisk hd1 = hdsf1.CreateHardDisk();
        MainBoard mainboard = new MainBoard(hd1);
        mainboard.ReadHD();

        HardDiskFactory hdsf2 = new HardDisk2Factory();
        HardDisk hd2 = hdsf2.CreateHardDisk();
        mainboard.Hd = hd2;
        mainboard.ReadHD();


        HardDiskFactory hdsf3 = new HardDisk3Factory();
        HardDisk hd3 = hdsf3.CreateHardDisk();
        mainboard.Hd = hd3;
        mainboard.ReadHD();
    }
此时,我们添加了一个类型的硬盘,也不再修改原来的硬盘生成方法,从而遵循了开放封闭原则.
如果我们再提出新的需求,即:我们购买品牌机,此时机器的主板,内存,硬盘,光驱等零部件都是由该品牌机的子工厂或相关原料工厂生产的,也就意味着
我们需要同一系列的内存,硬盘,光驱等零件,那么我们就可以采用抽象工厂方法来解决这个问题.我们再次改造工厂,代码如下:
首先是硬盘类,没有变化,如下:
public abstract class HardDisk
{
    public abstract void Read();
}

/// <summary>
/// HardDisk1为某一个具体品牌的硬盘
/// </summary>
public class HardDisk1 : HardDisk
{
    public override void Read()
    {
        HttpContext.Current.Response.Write("HardDisk1 is reading.<br/>");
    }
}

/// <summary>
/// HardDisk1为某一个具体品牌的硬盘
/// </summary>
public class HardDisk2 : HardDisk
{
    public override void Read()
    {
        HttpContext.Current.Response.Write("HardDisk2 is reading.<br/>");
    }
}
下面我们新建光驱类,光驱肯定也不只一种类型,可能一个品牌就会有一种类型的光驱:
public abstract class CD_ROM
{
    public abstract void Read();
}

public class CD_ROM1 : CD_ROM
{
    public override void  Read()
    {
 	    HttpContext.Current.Response.Write("CD_ROM1 is Reading CD.<br/>");
    }
}

public class CD_ROM2 : CD_ROM
{
    public override void  Read()
    {
 	    HttpContext.Current.Response.Write("CD_ROM2 is Reading CD.<br/>");
    }
}

此时,我们再次建立工厂类,此时的工厂要是生产的话,需要生产一个系列的产品,具体如下:

public abstract class HardWareFactory
{
    public abstract HardDisk CreateHardDisk();
    public abstract CD_ROM CreateCD_ROM();
}

public class HardWare1Factory : HardWareFactory
{
    public override HardDisk CreateHardDisk()
    {
        return new HardDisk1();
    }

    public override CD_ROM CreateCD_ROM()
    {
        return new CD_ROM1();
    }
}

public class HardWare2Factory : HardWareFactory
{
    public override HardDisk CreateHardDisk()
    {
        return new HardDisk2();
    }

    public override CD_ROM CreateCD_ROM()
    {
        return new CD_ROM2();
    }
}
重新再写主板类:
public class MainBoard
{
    private HardDisk hd;
    private CD_ROM cdrom;

    public MainBoard(HardDisk hd,CD_ROM cdrom)
    {
        this.hd = hd;
        this.cdrom = cdrom;
    }

    public HardDisk HD
    {
        get { return this.hd; }
        set { this.hd = value; }
    }

    public CD_ROM CD_ROM
    {
        get { return this.cdrom; }
        set { this.cdrom = value;}
    }

    public void ReadHD()
    {
        hd.Read();
    }

    public void ReadCD_ROM()
    {
        cdrom.Read();
    }
}

这是,我们的客户端再调用时,如下:

    protected void Page_Load(object sender, EventArgs e)
    {
        HardWareFactory hwf = new HardWare1Factory();
        HardDisk hd = hwf.CreateHardDisk();
        CD_ROM cdrom = hwf.CreateCD_ROM();

        MainBoard board = new MainBoard(hd, cdrom);
        board.ReadCD_ROM();
        board.ReadHD();


        hwf = new HardWare2Factory();
        hd = hwf.CreateHardDisk();
        cdrom = hwf.CreateCD_ROM();

        board = new MainBoard(hd, cdrom);
        board.ReadCD_ROM();
        board.ReadHD();
    }

页面效果如下:

image

至此,关于三个工厂,已经介绍完了.胡乱小结一下:

简单工厂:封装变化,创建对象,返回给客户使用.

工厂方法:封装变化,创建对象,返回给客户使用.同时避免了违反开放-封闭原则.

抽象工厂:创建一系列的对象,将创建好的对象返回给客户使用,同时遵循了开放-封闭原则.

posted @ 2009-08-30 15:17  Localhost  阅读(263)  评论(0编辑  收藏  举报