• 创建型模式篇(工厂模式Factory Pattern)


    一、工厂模式(Factory Pattern)

    1、定义:  在软件系统,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。提供一种封装机制来隔离这个对象的变化,从而保持系统中其他依赖这个变化对象的对象,就要用到工厂模式。

    2、目的:定义一个用户创建对象的接口,让子类决定实例化哪一个类,FactoryMethod使一个类的实例化延迟到它的子类。

    3、结构图:

    工厂模式:定义一个用于创建对象的接口,但是让子类决定实例化哪个类。也就是说在工厂模式中,核心的工厂类不在负责所有产品的创建,而是将具体创建工作交给它的子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不用接触哪一个产品类被实例化这种细节。

    现实工作中的例子:

    //设计日志记录类Log,支持记录的方法有FileLog和EventLog两种记录类型。
    //不用设计模式来实现:
    public class Log
    {
        public void WriteEvent()
        {
            Console.WriteLine("EventLog Success!");
        }
        public void WriteFile()
        {
            Console.WriteLine("FileLog Success!");
        }
        public void Write(string LogType)
        {
            switch(LogType.ToLower())
            {
                 case "event":
                     WriteEvent();
                    break;
                    
                case "file":
                    WriteFile();
                    break;
                    
                default:
                    break;
                                 
            }
        }
    }
    //这样程序结构显然不符合我们要求,加入要增加一种新的日志类型DataBaseLog,那么就要修改Log类,重新加入
    //switch语句不断在变化,这就引起了整个应用程序的不稳定,EventLog和FileLog是两种完全不同的记录方式
    //他们之前不存在必然的联系,应该把他们分别作为单独的对象来处理对待

    使用工厂模式来实现:

    思想是为EventLog和FileLog抽象出一个共同的父类,结构图如下:

    //首先抽象一个父类Log
    public abstact class Log
    {
        public abstract void Write();
    }
    //让EventLog和FileLog去继承父类,重写父类里的方法
    //EventLog类
    public class EventLog:Log
    {
        public override void Write()
        {
            Conosole.WriteLine("EventLog Write Success!");
        }
    }
    //FileLog类
    public class FileLog:Log
    {
        public override void Write()
        {
            Console.WriteLine("FileLog Write Success!");
        }
    }
    //现在再有一个新的日志记录方式DataBaseLog时候,只需要增加一个DataBaseLog子类去继承父类就可以
    //不用去修改EventLog和FileLog类,满足了类之间的层次关系,又很好的符合面向对象设计中的
    //单一职责原则,每一个类都只负责一件具体的事情。
    //但是我们并不确定客户程序去调用哪一种日志记录方式
    //也许会用到下面的语句:
    EventLog eventLog=new EventLog();
    eventLog.Write();
    //当日志记录方式从EventLog变成FileLog时候,我们就要修改程序中上面的创建对象语句。
    //这样的工作量可想而知,此时就需要解耦具体的日志记录方式,就可以引入工厂模式了
    //每一个日志记录的对象就是工厂所生成的产品,既然有两种记录方式,那就需要两个不同的工厂去生产。

    因此声明两个不同类型的工厂类:EventFactory类和FileFactory类

    //EventFactory类
    public class EventFactory
    {
        public EventLog Create()
        {
            return new EventLog();
        }
    }
    //FileFactory类
    public class FileFactory
    {
        public FileFactory Create()
        {
            return new FileLog();
        }
    }

    这两个工厂和具体的产品之间是平行的结构,并且一一对应,我们在他们两个基础上抽象出一个公用的接口:

    //LogFactory类
    public abstract class LogFactory
    {
        public abstract Log Create();
    }
    
    //EventFactory类
    public class EventFactory:LogFactory
    {
        public override EventLog Create()
        {
            return new EventLog();
        }
    }
    //FileFactory类
    public class FileFactory:LogFactory
    {
        public override FileFactory Create()
        {
            return new FileLog();
        }
    }
    //这样通过工厂模式,把上面对象创建工作封装在了工厂中,达到了具体应用程序
    //和具体日志记录方式对象之间的解耦
    //客户端调用代码
    publc class Test
    {
        public static void Main(string[] args)
        {
            LogFactory factory=new EventFactory();
            Log log=factory.Create();
            log.Write();
        }
    }

    在应用程序中,Log对象创建是频繁的,要是换成另一种日志记录方式,只需要修改为:

    LogFactory factory=new FileFactory()

    其他任何地方都不需要修改,我们也可以说个.net的特性,避免这种不必要的修改,利用.net的反射机制来进行实现,所以就要用到配置文件了,如果我们想用哪一种日志记录方式,就在相应的配置文件中设置如下:

    <appSettings>
        <add key="factoryName" value="EventFactory"></add?
    </appSettings>

    然后客户端代码可以这样写:

    //客户端调用代码
    publc class Test
    {
        public static void Main(string[] args)
        {
            string strFactoryName=ConfigurationSettings.AppSettings["factoryName"];//引入配置文件
            LogFactory factory;
            factory=(LogFactory)Assembly.Load("FactoryMethod").CreateInstance("FactoryMethod"+strFactoryName);
            Log log=factory.Create();
            log.Write();
        }
    }
  • 相关阅读:
    动态SQL的注意
    关于数据库抛出异常:Incorrect string value: 'xE1x...' for column '字段名' at row 1 问题的解决方法
    让.bashrc文件在终端自动生效
    期中考试题
    RAP、Mock.js、Vue.js、Webpack
    全局变量变为局部变量 & MVC思想
    用 JS + LeanCloud 给网页添加数据库(留言功能)
    闭包的使用
    从发请求到AJAX到同源政策
    从实现HTML页面局部刷新到JSONP
  • 原文地址:https://www.cnblogs.com/drq1/p/8580038.html
Copyright © 2020-2023  润新知