Spark涉及的设计模式-创建型-工厂方法模式

Spark涉及的设计模式-创建型-工厂方法模式


说在前面的话:

说到工厂方法模式不得不说的就是简单工厂模式(又名静态方法模式),简单工厂模式就是他的行为就很简单,就是定义一个接口用来创建对象。但是它创建工厂类的时候是通过客户端传入参数进行决定创建什么工厂的。这样如果需要添加一个工厂那么就需要改变这个工厂类。这样就违背了开闭原则。而工厂方法模式则不通,他是通过客户端就决定实例化哪个工厂进行决定的,这样需要修改的是客户端和添加新的工厂类

这里我们以RPC为参考

工厂接口

工厂方法模式肯定是要继承一个工厂接口的,在SparkRPC的工厂方法中也不会例外,当然这里的接口是特质,特质和类的不同就是一个子类中可以混入多个特质

/**
 * A factory class to create the [[RpcEnv]]. It must have an empty constructor so that it can be
 * created using Reflection.
 */
private[spark] trait RpcEnvFactory {

  def create(config: RpcEnvConfig): RpcEnv
}

工厂实现

继承这个特质的类仅有NettyRpcEnvFactory,也就是RpcEnvFactory仅有一个工厂实现

private[rpc] class NettyRpcEnvFactory extends RpcEnvFactory with Logging {

  def create(config: RpcEnvConfig): RpcEnv = {
    val sparkConf = config.conf
    // Use JavaSerializerInstance in multiple threads is safe. However, if we plan to support
    // KryoSerializer in future, we have to use ThreadLocal to store SerializerInstance
    val javaSerializerInstance =
      new JavaSerializer(sparkConf).newInstance().asInstanceOf[JavaSerializerInstance]
    val nettyEnv =
      new NettyRpcEnv(sparkConf, javaSerializerInstance, config.advertiseAddress,
        config.securityManager, config.numUsableCores)
    if (!config.clientMode) {
      val startNettyRpcEnv: Int => (NettyRpcEnv, Int) = { actualPort =>
        nettyEnv.startServer(config.bindAddress, actualPort)
        (nettyEnv, nettyEnv.address.port)
      }
      try {
        Utils.startServiceOnPort(config.port, startNettyRpcEnv, sparkConf, config.name)._1
      } catch {
        case NonFatal(e) =>
          nettyEnv.shutdown()
          throw e
      }
    }
    nettyEnv
  }
}

客户端

有了工厂之后,使用改工厂的类也就是客户端,就可以很方便地就实例化一个RpcEnv的产品。下面看一下具体的客户端代码。也就是最后代码中的new NettyRpcEnvFactory().create(config),这里创建了一个RpcEnv的Rpc通信环境。

private[spark] object RpcEnv {

  def create(
      name: String,
      host: String,
      port: Int,
      conf: SparkConf,
      securityManager: SecurityManager,
      clientMode: Boolean = false): RpcEnv = {
    create(name, host, host, port, conf, securityManager, 0, clientMode)
  }

  def create(
      name: String,
      bindAddress: String,
      advertiseAddress: String,
      port: Int,
      conf: SparkConf,
      securityManager: SecurityManager,
      numUsableCores: Int,
      clientMode: Boolean): RpcEnv = {
    val config = RpcEnvConfig(conf, name, bindAddress, advertiseAddress, port, securityManager,
      numUsableCores, clientMode)
    new NettyRpcEnvFactory().create(config)
  }
}

为什么不用抽象工厂模式

那么思考一下这里为什么使用的是工厂方法模式而不是抽象工厂模式

这是因为抽象工厂模式支持的场景不同。

抽象工厂模式的产生是解决了工厂方法模式中每个工厂仅仅生产一个产品,如果存在需要两个产品混合的产品那么就需要再次创建工厂如此这样造成的工厂类冗杂问题。但是此例中我们不需要其他的产品。既是是SparkRpc从Akka转移到Netty中时也仅仅需要创建新的实现工厂而不是进行产品的整合。

就需要再次创建工厂如此这样造成的工厂类冗杂问题。但是此例中我们不需要其他的产品。既是是SparkRpc从Akka转移到Netty中时也仅仅需要创建新的实现工厂而不是进行产品的整合。

此场景中NettyRpcEnv的职责就仅仅是生产RpcEnv,而在Spark架构中我们需要的也仅仅是RpcEnv这一个产品并不需要其他的Rpc产品。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天心有情

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值