工厂模式在Logback以及Dubbo源码中的应用

创建型模式

目录

1、工厂模式

1.1 工厂模式的UML类图

1.2 日常生活看工厂模式

1.3 具体例子——拍摄《速度与激情8》需要车库外的车为例

1.4 另一个例子,实现加减乘除,简单工厂模式与工厂模式异同比较

2、工厂模式在Logback源码中的应用

3、工厂模式在Dubbo源码中的应用

4、简单工厂和工厂的区别

4.1 简单工厂模式优点

4.2 工厂模式

4.3 工厂模式优点

4.4 工厂模式缺点


1、工厂模式

工厂模式方法(factory method),定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类。

1.1 工厂模式的UML类图

C# 工厂方法模式

1.2 日常生活看工厂模式

《速度与激情》范·迪塞尔要去参加五环首届跑车拉力赛的场景。因为要拍摄《速度与激情8》,导演组车的种类增多了,阵容也更加豪华了,加上导演古怪的性格可能每一场戏绝对需要试驾几十种车。如果车库没有的车(具体产品类)可以由场务(具体工厂类)直接去4S店取,这样没增加一种车(具体产品类)就要对应的有一个场务(具体工厂类),他们互相之间有着各自的职责,互不影响,这样可扩展性就变强了。

1.3 具体例子——拍摄《速度与激情8》需要车库外的车为例

抽象工厂代码:

namespace CNBlogs.DesignPattern.Common
{
    public interface IFactory
    {
        ICar CreateCar();
    }
}

抽象产品代码:

namespace CNBlogs.DesignPattern.Common
{
    public interface ICar
    {
        void GetCar();
    }
}

具体工厂代码:

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    ///  具体工厂类: 用于创建跑车类
    /// </summary>
    public class SportFactory : IFactory
    {
        public ICar CreateCar()
        {
            return new SportCar();
        }
    }

    /// <summary>
    ///  具体工厂类: 用于创建越野车类
    /// </summary>
    public class JeepFactory : IFactory
    {
        public ICar CreateCar()
        {
            return new JeepCar();
        }
    }

    /// <summary>
    ///  具体工厂类: 用于创建两厢车类
    /// </summary>
    public class HatchbackFactory : IFactory
    {
        public ICar CreateCar()
        {
            return new HatchbackCar();
        }
    }
}

具体产品代码:

namespace CNBlogs.DesignPattern.Common
{
    /// <summary>
    /// 具体产品类: 跑车
    /// </summary>
    public class SportCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("场务把跑车交给范·迪塞尔");
        }
    }

    /// <summary>
    /// 具体产品类: 越野车
    /// </summary>
    public class JeepCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("场务把越野车交给范·迪塞尔");
        }
    }

    /// <summary>
    /// 具体产品类: 两箱车
    /// </summary>
    public class HatchbackCar : ICar
    {
        public void GetCar()
        {
            Console.WriteLine("场务把两箱车交给范·迪塞尔");
        }
    }
}

客户端代码:

namespace CNBlogs.DesignPattern
{
    using System.IO;
    using System.Configuration;
    using System.Reflection;
    using CNBlogs.DesignPattern.Common;

    class Program
    {
        static void Main(string[] args)
        {
            // 工厂类的类名写在配置文件中可以方便以后修改
            string factoryType = ConfigurationManager.AppSettings["FactoryType"];

            // 这里把DLL配置在数据库是因为以后数据可能发生改变
            // 比如说现在的数据是从sql server取的,以后需要从oracle取的话只需要添加一个访问oracle数据库的工程就行了
            string dllName = ConfigurationManager.AppSettings["DllName"];

            // 利用.NET提供的反射可以根据类名来创建它的实例,非常方便
            var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            string codeBase = currentAssembly.CodeBase.ToLower().Replace(currentAssembly.ManifestModule.Name.ToLower(), string.Empty);
            IFactory factory = Assembly.LoadFrom(Path.Combine(codeBase, dllName)).CreateInstance(factoryType) as IFactory;
            ICar car = factory.CreateCar();
            car.GetCar();
        }
    }
}

1.4 另一个例子,实现加减乘除,简单工厂模式与工厂模式异同比较

1.4.1 简单工厂模式实现加减乘除

在这个例子中,只需要输入运算符,工厂就实例化出合适的对象,通过多态返回父类的方式实现了计算器的结果。而客户端只要这样调用就可以了,如下:

1.4.2 工厂模式实现加减乘除

就要先创建一个工厂接口,然后加减乘除各建一个工厂方法去实现这个接口。例子如下:

参考例子:https://blog.csdn.net/abc709272013/article/details/52654266

2、工厂模式在Logback源码中的应用

 

我们再看logback中的一些应用:

public interface ILoggerFactory {
  
  /**
   * Return an appropriate {@link Logger} instance as specified by the
   * <code>name</code> parameter.
   * 
   * <p>If the name parameter is equal to {@link Logger#ROOT_LOGGER_NAME}, that is 
   * the string value "ROOT" (case insensitive), then the root logger of the 
   * underlying logging system is returned.
   * 
   * <p>Null-valued name arguments are considered invalid.
   *
   * <p>Certain extremely simple logging systems, e.g. NOP, may always
   * return the same logger instance regardless of the requested name.
   * 
   * @param name the name of the Logger to return
   * @return a Logger instance 
   */
  public Logger getLogger(String name);
}

这个接口下边只有一个方法,我们看一下他的实现,在这三个类中

也就是把这个抽象方法教给子类来实现,我们来看一下类图

Logback在创建Log时,使用的就是工厂方法。它的各个元素都是在同一个类sun.rmi.runtime的Log.java中用内部类实现,但这并不影响工厂方法的结构。它的抽象产品基类就是Log,其中一个产品实现类为LoggerLog,抽象工厂类为LogFactory,工厂实现类为LoggerLogFactory。另一对是LogStreamLog和LogStreamLogFactory。其中关键代码如下,为了更加易懂,我调整了一下源码顺序:

public abstract class Log {
  
    ... ...
    public abstract void log(Level var1, String var2);
    
    private interface LogFactory {
        Log createLog(String var1, String var2, Level var3);
    }
    
    private static class LoggerLog extends Log {
        public void log(Level var1, String var2) {
            if (this.isLoggable(var1)) {
                String[] var3 = Log.getSource();
                this.logger.logp(var1, var3[0], var3[1], Thread.currentThread().getName() + ": " + var2);
            }
        }
    }

    private static class LoggerLogFactory implements Log.LogFactory {
        public Log createLog(String var1, String var2, Level var3) {
            Logger var4 = Logger.getLogger(var1);
            return new Log.LoggerLog(var4, var3);
        }
    }
    
    private static class LogStreamLog extends Log {
        public void log(Level var1, String var2) {
            if (this.isLoggable(var1)) {
                String[] var3 = Log.getSource();
                this.stream.println(unqualifiedName(var3[0]) + "." + var3[1] + ": " + var2);
            }
        }
    }

    private static class LogStreamLogFactory implements Log.LogFactory {
        public Log createLog(String var1, String var2, Level var3) {
            LogStream var4 = null;
            if (var2 != null) {
                var4 = LogStream.log(var2);
            }
            return new Log.LogStreamLog(var4, var3);
        }
    }
}

3、工厂模式在Dubbo源码中的应用

     ServiceConfig中有个字段,代码是这样的: 

     查看文本打印 

   private static final Protocol protocol =ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();  

  Dubbo里有很多这种代码。这也是一种工厂模式,只是实现类的获取采用了jdkspi的机制。这么实现的优点是可扩展性强,想要扩展实现,只需要在classpath下增加个文件就可以了,代码零侵入。另外,像上面的Adaptive实现,可以做到调用时动态决定调用哪个实现,但是由于这种实现采用了动态代理,会造成代码调试比较麻烦,需要分析出实际调用的实现类。

4、简单工厂和工厂的区别

4.1 简单工厂模式优点

工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。

就像这个计算器,让客户端不用管该用哪个类的实例,只需要把“+”给工厂,工厂自动就给出了相应的实例,客户端只要去运算就可以了,不同的实例会实现不同的运算。

4.2 工厂模式

工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。你想要加功能,本来是要改工厂类的,而现在是修改客户端。

4.3 工厂模式优点

工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。

这两者都是集中封装了对象的创建,使得要更换对象时,不需要做大的改动就可实现,降低了客户程序与产品对象的耦合。

工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。

4.4 工厂模式缺点

缺点是由于每加一个产品,就需要加一个产品工厂的类,增加了额外的开发量。

 

参考文章:

https://www.cnblogs.com/toutou/p/4899388.html

https://blog.csdn.net/abc709272013/article/details/52654266

https://blog.csdn.net/weixin_41657493/article/details/88361421

https://blog.csdn.net/Leon_Jinhai_Sun/article/details/90692168?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

https://blog.csdn.net/zuoanyinxiang/article/details/51330415

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值