scala设计模式之工厂模式

2020-07-06  本文已影响0人  百年叔叔

一、简介

工厂模式主要是为创建对象提供接口,工厂模式大体可以分为三类:
1.简单工厂模式(Simple Factory)
2.工厂方法模式 (Factory Method)
3.抽象工厂模式 (Abstract Factory)

二、简单工厂模式

我以前做过一个排队项目,里面有一个需求是如果排到这位司机了要用微信通知司机轮到他了。但是后续增加了短信通知,电话通知,邮件通知司机所属客户。

1.首先我们定义一个消息的基类,(接口也可以),这是消息的抽象类。
/**
 * description: MyMessageFactory 
 * date: 2020/7/6 20:53 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:消息发送的基类
 */
abstract class MyMessage {
  /**
   * 消息的类型
   */
  def message()

}
2.产品的具体实现

先来一份短信发送实现(具体的产品类):

/**
 * description: SmsMessage 
 * date: 2020/7/6 20:55 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:短信发送的具体实现
 */
class SmsMessage extends MyMessage {
  /**
   * 消息的类型
   */
  override def message(): Unit = {
    println("我是短信发送!")
  }

}

微信发消息的具体实现

/**
 * description: SmsMessage 
 * date: 2020/7/6 20:55 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:微信发送消息的实现
 */
class WeChatMessage extends MyMessage {
  /**
   * 消息的类型
   */
  override def message(): Unit = {
    println("我是微信发送!")
  }

}

邮件发送消息的具体实现


/**
 * description: SmsMessage 
 * date: 2020/7/6 20:55 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:邮件发送消息的具体实现
 */
class MailMessage extends MyMessage {
  /**
   * 消息的类型
   */
  override def message(): Unit = {
    println("我是邮件发送!")
  }

}
3.准备工作完成了,我们来一个简单工厂,消息发送如下:

/**
 * description: MyMessageFactory 
 * date: 2020/7/6 20:58 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:消息发送简单工厂
 */
object MyMessageFactory {
  //短信
  val SMS: Int = 1
  //微信
  val WECHAT: Int = 2
  //邮件
  val MAIL: Int = 3

  def createMessage(i: Int): MyMessage = {
    var mymesage: MyMessage = null
    i match {
      case 1 => mymesage = new SmsMessage
      case 2 => mymesage = new WeChatMessage
      case 3 => mymesage = new MailMessage
    }
    mymesage
  }

}
4.发送消息(我们这里先测试发送邮件)
/**
 * description: OrderPizza 
 * date: 2020/7/6 18:10 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:发送消息
 */
object OederMessage {

  def main(args: Array[String]): Unit = {
    val m = MyMessageFactory.createMessage(MyMessageFactory.MAIL)
    m.message();
  }

}
image.png
5.总结

1.简单工厂是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2.create()方法通常是静态的,所以也称之为静态工厂。
缺点:
1 扩展性差(我想增加一种消息发送方式,除了新增一个消息发送类,还需要修改工厂类方法)
2 不同的产品需要不同额外参数的时候 不支持。

二、工厂方法模式

1.模式描述

提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例。

2.模式作用

可以一定程度上解耦,消费者和产品实现类隔离开,只依赖产品接口(抽象产品),产品实现类如何改动与消费者完全无关。

可以一定程度增加扩展性,若增加一个产品实现,只需要实现产品接口,修改工厂创建产品的方法,消费者可以无感知(若消费者不关心具体产品是什么的情况)。
可以一定程度增加代码的封装性、可读性。清楚的代码结构,对于消费者来说很少的代码量就可以完成很多工作。
另外,抽象工厂才是实际意义的工厂模式,工厂方法只是抽象工厂的一个比较常见的情况。

3.适用场景

消费者不关心它所要创建对象的类(产品类)的时候。

消费者知道它所要创建对象的类(产品类),但不关心如何创建的时候。

例如:hibernate里通过sessionFactory创建session、通过代理方式生成ws客户端时,通过工厂构建报文中格式化数据的对象。

4.模式要素

提供一个产品类的接口。产品类均要实现这个接口(也可以是abstract类,即抽象产品)。
提供一个工厂类的接口。工厂类均要实现这个接口(即抽象工厂)。
由工厂实现类创建产品类的实例。工厂实现类应有一个方法,用来实例化产品类。

5.实例代码

首先我们定义一个工厂

/**
 * description: IMyMessageFactory 
 * date: 2020/7/7 8:23 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:工厂方法模式_工厂接口
 */
trait IMyMessageFactory {

  def createMessage(messageType:Int):IMyMessage

}

接着定义工厂的实现


/**
 * description: MyMessageFactory 
 * date: 2020/7/6 20:58 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:消息发送工厂的实现
 */
object MyMessageFactory extends IMyMessageFactory {

  //短信
  val SMS: Int = 1
  //微信
  val WECHAT: Int = 2
  //邮件
  val MAIL: Int = 3


  override def createMessage(messageType: Int): IMyMessage = {

    // 这里的方式是:消费者知道自己想要什么产品;若生产何种产品完全由工厂决定,则这里不应该传入控制生产的参数。
    var myMessage: IMyMessage = null
    var messageParam: Map[String, String] = Map()
    // 根据某些条件去选择究竟创建哪一个具体的实现对象,条件可以传入的,也可以从其它途径获取。
    messageType match {
      case 1 => myMessage = new SmsMessage; messageParam += ("SMS" -> "13318578765")
      case 2 => myMessage = new WeChatMessage; messageParam += ("WECHAT" -> "bainianshushu")
      case 3 => myMessage = new MailMessage; messageParam += ("EMAIL" -> "test@test.com")
      case _ => myMessage = new MailMessage; messageParam += ("EMAIL" -> "test@test.com")
    }
    myMessage.setMessageParam(messageParam)
    myMessage
  }
}

接着定义产品的接口

/**
 * description: IMyMessage 
 * date: 2020/7/7 8:26 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:产品接口
 */
trait IMyMessage {
  
  def getMessageParam:Map[String,String]

  def setMessageParam(messageParam:Map[String,String])

  // 发送通知/消息
  def sendMessage(str:String)
}

虚拟产品类

/**
 * description: MyAbstractMessage 
 * date: 2020/7/7 8:25 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:虚拟产品类
 */
abstract class MyAbstractMessage extends IMyMessage {

  // 这里可以理解为生产产品所需要的原材料库。最好是个自定义的对象,这里为了不引起误解使用Map。
  var messageParam: Map[String, String] = _


  override def getMessageParam: Map[String, String] = messageParam

  override def setMessageParam(messageParam: Map[String, String]): Unit = {

    this.messageParam = messageParam

  }
}

短信产品


/**
 * description: SmsMessage 
 * date: 2020/7/6 20:55 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:短信发送的具体实现
 */
class SmsMessage extends MyAbstractMessage  {
  /**
   * 定义发送短信的方法
   */
  override def sendMessage(str:String): Unit = {

    if (null == getMessageParam || null == getMessageParam.get("SMS") || "".equals(getMessageParam.get("SMS").getOrElse())) {
      throw new Error("发送短信,需要传入接收人参数")
    }

    printf("我是企业号码 %s 发送短信,我正在给 %s 发送短信 \n",getMessageParam.get("SMS").getOrElse(),str)
  }

}

微信产品


/**
 * description: SmsMessage 
 * date: 2020/7/6 20:55 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:微信发送消息的实现
 */
class WeChatMessage extends MyAbstractMessage  {
  /**
   * 定义发送微信的方法
   */
  override def sendMessage(str:String): Unit = {

    if (null == getMessageParam || null == getMessageParam.get("WECHAT") || "".equals(getMessageParam.get("WECHAT").getOrElse())) {
      throw new Error("发送微信,需要传入EMAIL参数")
    }

    printf("我是企业号码 %s 发送微信,我正在给 %s 发送微信 \n",getMessageParam.get("WECHAT").getOrElse(),str)
  }

}

邮件产品


/**
 * description: SmsMessage 
 * date: 2020/7/6 20:55 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:邮件发送消息的具体实现
 */
class MailMessage extends MyAbstractMessage {

  /**
   * 定义发送邮件的方法
   */
  override def sendMessage(str:String): Unit = {

    if (null == getMessageParam || null == getMessageParam.get("EMAIL") || "".equals(getMessageParam.get("EMAIL").getOrElse())) {
      throw new Error("发送邮件,需要传入EMAIL参数")
    }
    printf("我是企业号码 %s 发送邮件,我正在给 %s 发送邮件 \n",getMessageParam.get("EMAIL").getOrElse(),str)
  }
}

最后我们来一个消费者

/**
 * description: OrderPizza 
 * date: 2020/7/6 18:10 
 * version: 1.0
 *
 * @author 阳斌
 *         邮箱:1692207904@qq.com 
 *         类的说明:工厂方法模式_消费者类
 */
object MyFactoryMethodMain {

  def main(args: Array[String]): Unit = {
    val m: IMyMessageFactory = MyMessageFactory
    var myMessage: IMyMessage = null
    // 对于这个消费者来说,不用知道如何生产message这个产品,耦合度降低

    // 先来一个短信通知
    myMessage = m.createMessage(MyMessageFactory.SMS)
    myMessage.sendMessage("18614234421")
    //邮件通知
    myMessage = m.createMessage(MyMessageFactory.MAIL)
    myMessage.sendMessage("163@163.com")
    //微信通知
    myMessage = m.createMessage(MyMessageFactory.WECHAT)
    myMessage.sendMessage("bainian")

  }

}

结果


image.png
上一篇下一篇

猜你喜欢

热点阅读