设计模式之工厂方法(三)

前面一篇已经说了简单工厂,那就趁热打铁,开始讲述工厂方法吧。

一、引出模式

开发场景:实现一个导出数据的应用框架,让客户来选择导出数据的方式,并执行真正的数据导出。

导出数据的方式可以是导出到文本文件,导出到XML,导出到Excel,导出到数据库等。

好了,我们大概来想一下思路,对于上面的应用框架,导出来的都是一个数据文件,系统并不知道导出的是哪种文件,所以我们可以定义一个统一的导出数据的接口(IDataExport),对于实现导出数据的业务功能对象来说(Client),它应该根据需求来创建相应的IDataExport的实现对象,可是对于实现导出数据的业务功能对象(Client)而已,它并不知道应该创建哪一个IDataExport的实现对象,也不知道如何创建。

也就是说,客户端是需要创建IDataExport具体的实例对象的,但是客户端只知道IDataExport接口,并不知道具体的实现,那怎么办呢?

二、认识模式

1.模式定义

定义一个创建对象的接口,让子类决定去实例化哪个类,工厂方法使一个类的实例延迟到子类。

2.解决思路

在实现数据导出业务对象(Client)里,我们根本不知道该使用哪种导出方式,因此这个对象就不能和具体数据导出对象耦合在一起,它需面对数据导出的接口,但是接口不能直接使用的,需要用到具体的实现对象的实例。

这样不就矛盾了吗?那怎么办?

说白了,客户端不就是需要一个具体实现类的对象吗,那好我就用个方法来帮你创建这个实例对象,这个方法自己也不知道它将被用来干嘛,我们可以将这个方法定义成抽象方法,它就当成摆设吧,具体的创建实例的工作就交给它的子类吧,那么这个对象本身就可以只是面对接口编程,而无需关系具体类的创建工作。

3.模式结构

IDataExport:定义工厂方法所创建的对象的接口,也就是client需要使用的对象的接口。

ExportToTxt:具体的IDataExport接口的实现对象。

IFactoryMethod:创建器,声明工厂方法,工厂方法通常会返回一个IDataExport类型的实例对象,里面大多是抽象方法。也可以提供默认实现。

CreatForTxt:具体的创建器对象,实现IFactoryMethod定义的工厂方法,返回具体的IFactoryMethod实例。

4.示例代码

 class Program
    {
        static void Main(string[] args)
        {

            //最关键一步,改变了new的对象,也就改变了具体的实现
            IFactoryMethod factory = new CreateForSql();
            IDataExport export = factory.Create();
            export.Export(); 

            Console.ReadKey();
        }
    }

    #region 工厂

    public interface IFactoryMethod
    {
        IDataExport Create();

    }

    public class CreateForTxt : IFactoryMethod
    {
        public IDataExport Create()
        {
            return new ExportToTxt();
        }
    }

    public class CreateForSql : IFactoryMethod
    {
        public IDataExport Create()
        {
            return new ExportToSql();
        }
    }

    public class CreateForXml : IFactoryMethod
    {
        public IDataExport Create()
        {
            return new ExportToXml();
        }
    }
    #endregion

    #region 产品

    public interface IDataExport
    {
        void Export();
    }

    public class ExportToTxt : IDataExport
    {

        public ExportToTxt()
        {

        }

        public void Export()
        {
            Console.WriteLine("数据导出到txt");
        }
    }

    public class ExportToSql : IDataExport
    {
        public void Export()
        {
            Console.WriteLine("数据导出到数据库");
        }
    }

    public class ExportToXml : IDataExport
    {
        public void Export()
        {
            Console.WriteLine("数据导出到xml");
        }
    }
    #endregion 

三、理解模式

1.模式功能

工厂方法模式主要功能是让父类不知道具体实现情况下,完成自身的功能调用;而具体的实现则延迟到子类来实现。

2.谁来使用工厂方法创建的对象

事实上,在工厂方法模式里面,应该是IFactoryMethod中的其他方法在使用工厂方法创建的对象,虽然也可以把工厂方法创建的对象直接提供给IFactoryMethod外部使用,但工厂方法的本意,是由IFactoryMethod对象内部的方法来使用工厂方法创建的对象,也就是说,工厂方法一般不提供给IFactoryMethod外部使用。

1)客户端使用IFactoryMethod对象的情况

 客户端:

class Program
    {
        static void Main(string[] args)
        {

            #region 客户端使用IFactoryMethod对象(推荐)

            IFactoryMethod factory = new CreateForSql();
            factory.export();
            #endregion

            Console.ReadKey();
        }
    }

抽象工厂类

 public abstract class IFactoryMethod
    {
        /// <summary>
        /// 抽象方法
        /// </summary>
        /// <returns></returns>
        public abstract IDataExport Create();

        /// <summary>
        /// 依赖注入 setter方法
        /// </summary>
        public void export()
        {
            IDataExport export = Create();
            export.Export();
        }
    }

2)客户端使用由IFactoryMethod创建出来的对象

这比较好理解,示例代码用的就是这种情况

客户端

class Program
{
        static void Main(string[] args)
        {

            #region 客户端使用IFactoryMethod创建的对象(不推荐)
            IFactoryMethod factory = new CreateForSql();
            IDataExport export = factory.Create();
            export.Export(); 
            #endregion
            Console.ReadKey();
     }
}

抽象工厂类

public interface IFactoryMethod
{
      IDataExport Create();
}

 

小结:在工厂方法模式中,客户端要么使用IFactoryMethod对象,要么使用IFactoryMethod创建的对象,一般客户端不直接使用工厂方法。当然也可以直接把工厂方法暴露给客户端操作,但是一般不这么做。

3.模式优点

1)可以在不知具体实现的情况下编程

工厂方法模式可以让你在实现功能时,如果需要某个产品对象,只需要使用产品的接口即可,而无需关系具体的实现。选择具体的实现的任务延迟到子类去完成。

2)更容易扩展对象的新版本

只需要新加入一个子类来提供新的工厂方法实现,然后在客户端使用这个新的子类即可。

3) 连接平行的类层次结构

4.模式缺点

具体产品对象和工厂方法的耦合

5.模式本质

工厂方法模式的本质就是延迟到子类来选择实现。

与简单工厂的区别:从本质上讲,在具体实现上都是“选择实现”,但是简单工厂是直接在工厂类中进行“选择实现”;而工厂方法会把这个工作延迟到子类来实现,工厂类里面的工厂方法是依赖于抽象而不是具体的实现。

6.模式选择

1) 如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类中去实现。

2) 如果一个类本身希望由它的子类来创建所需的对象的时候,应该使用工厂方法模式。

posted @ 2013-11-07 14:12  烧点饭  阅读(1357)  评论(2编辑  收藏  举报