设计模式 ~ 工厂模式

1、简单工厂模式

  • 定义:简单工厂模式又名静态工厂方法模式,是由一个工厂对象决定创建出哪一种产品类的实例,包含:
    • 产品工厂类(Factory):负责生产各种具体的产品,不关心产品产生的过程,只关心要生产的产品的类型
    • 抽象产品类(IProduct):创建的所有对象的父类,它负责描述所有实例所共有的公共接口
    • 具体产品类(Product):具体的产品,封装了产品建造的过程以及使用的教程
  • 简单实现
    • 不同手机型号需要使用不同的推送,可以集成小米、华为、极光推送然后创建一个工厂类根据手机型号来使用不同的推送。
    • 1、定义推送调用的接口
/**
 * 定义一个通用的push推送接口
 * @author LTP  2021/11/10
 */
interface IPush {
    /** 定义一个抽象的push方法 */
    fun push()
}
  • 2、封装不同的推送调用方法
/**
* 具体产品类:小米推送具体实现
* @author LTP  2021/11/10
*/
class MiPush : IPush {

   override fun push() {
       println("小米手机使用小米推送")
   }
}
/**
 * 具体产品类:华为推送具体实现
 * @author LTP  2021/11/10
 */
class HuaWeiPush : IPush {

    override fun push() {
        println("华为手机使用华为推送")
    }
}
/**
 * 具体产品类:极光推送具体实现
 * @author LTP  2021/11/10
 */
class JiGuangPush : IPush {

    override fun push() {
        println("其他手机使用极光推送")
    }
}
  • 3、创建一个push工厂
/**
 * 推送工厂类
 * @author LTP  2021/11/10
 */
object PushFactory {

    /**
     * 根据具体的手机类型使用具体的推送服务
     *
     * @param type 推送类型
     * @return Push 具体的推送类型
     */
    fun createPush(type: String): IPush {
        return when (type) {
            "xiaoMi" -> MiPush()
            "huaWei" -> HuaWeiPush()
            else -> JiGuangPush()
        }
    }
}
  • 4、具体使用
/**
 * 具体调用
 *
 * @author LTP  2021/11/10
 */
class CreatePush {

    companion object {
        @JvmStatic
        fun main(args: Array) {
            PushFactory.createPush("xiaoMi").push()
            PushFactory.createPush("huaWei").push()
        }
    }
}
执行结果:
小米手机使用小米推送
华为手机使用华为推送
  • 使用场景与优缺点
    • 使用场景
      • 1、工厂类负责创建的对象比较少。
      • 2、客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心
    • 优点:用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性
    • 缺点:类型在编译期间已经被确定,增加新类型需要修改工厂,违背了开放封闭原则(ASD) ;需要事先知道所有要生成的类型,当子类过多或者子类层次过多时不适合使用

2、工厂方法模式

  • 定义:定义一个用于创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的实例化延迟到其子类,包含:
    • Product:抽象产品类。
    • ConcreteProduct:具体产品类,实现Product接口。
    • Factory:抽象工厂类,该方法返回一个Product类型的对象。
    • ConcreteFactory:具体工厂类,返回ConcreteProduct实例。
  • 简单实现
    • 现在来了一个新需求,在原来基础上oppo手机需加入oppo推送,而且后面可能还会有更多手机厂商的推送...
    • 实现步骤
      • 在原来的基础上加一层抽象工厂类
    /**
     * 推送抽象工厂类
     * @author LTP  2021/11/10
     */
    abstract class AbsPushFactory {

          abstract fun  createPush(clazz: Class): T
    }
  • 原来的工厂类继承抽象工厂类利用反射来初始化各产品对象
    /**
     * @author LTP  2021/11/10
     */
  object PushFactory : AbsPushFactory() {

      override fun  createPush(clazz: Class): T {
           return Class.forName(clazz.name).getDeclaredConstructor().newInstance() as T
    }
}
  • 这是加入跟以前小米华为一样,添加oppo推送的具体产品类......
/**
 * 具体产品类:Oppo推送具体实现
 * @author LTP  2021/11/10
 */
class OppoPush : IPush {

    override fun push() {
        println("oppo手机使用oppo推送")
    }
}
  • 最终的调用
/**
 * 具体调用
 * 
 * @author LTP  2021/11/10
 */
class CreatePush {

    companion object {
        @JvmStatic
        fun main(args: Array) {
            PushFactory.createPush(MiPush::class.java).push()
            PushFactory.createPush(HuaWeiPush::class.java).push()
            PushFactory.createPush(OppoPush::class.java).push()
        }
    }
}
执行结果:
小米手机使用小米推送
华为手机使用华为推送
oppo手机使用oppo推送
  • 优点:可以自由新增更多的产品线而不破坏开放封闭原则
  • 缺点:使用反射,多多少少影响性能

3、抽象工厂模式

  • 定义:为创建一组相关或者相互依赖的对象提供一个接口,而无需指定它们的具体类;
    • AbstractFactory:抽象工厂,它声明了用来创建不同产品的方法。
    • ConcreteFactory:具体工厂,实现抽象工厂中定义的创建产品的方法。
    • AbstractProduct:抽象产品,为每种产品声明业务方法。
    • ConcreteProduct:具体产品,定义具体工厂生产的具体产品,并实现抽象产品中定义的业务方法。
  • 新需求
    • 添加针对向不同的手机厂商发短信
  • 实现
    • 1、添加一个Isend接口
/**
 * 定义一个通用的发送短信接口
 * @author LTP  2021/11/10
 */
interface ISend {
    /** 定义一个抽象的send方法 */
    fun send()
}
  • 2、华为小米分别添加对Isend的实现
/**
 * 具体产品类:小米短信具体实现(华为代码同理已省略)
 * @author LTP  2021/11/10
 */
class MiSend : ISend {

    override fun send() {
        println("小米手机发送小米短信")
    }
}
  • 3、添加包含push和send的抽象工厂
/**
 * 推送发短信抽象工厂类
 * @author LTP  2021/11/10
 */
abstract class AbsPushSendFactory {

    abstract fun createPush(): IPush
    abstract fun createSend(): ISend
}
  • 4、分别实现华为工厂和小米工厂(代码一样已省略)
/**
 * 华为工厂类
 *
 * @author LTP  2021/11/10
 */
class HuaWeiFactory : AbsPushSendFactory() {

    override fun createPush(): IPush {
        return HuaWeiPush()
    }

    override fun createSend(): ISend {
        return HuaWeiSend()
    }
}
  • 5、具体调用
/**
 * 具体调用
 *
 * @author LTP  2021/11/10
 */
class CreatePushSend {

    companion object {
        @JvmStatic
        fun main(args: Array) {
            // 小米工厂
            val miFactory = MiFactory()
            miFactory.createPush().push()
            miFactory.createSend().send()

            // 华为工厂
            val huaWeiFactory = HuaWeiFactory()
            huaWeiFactory.createPush().push()
            huaWeiFactory.createSend().send()
        }
    }
}
执行结果:
小米手机使用小米推送
小米手机发送小米短信
华为手机使用华为推送
华为手机发送华为短信
  • 使用场景与优缺点
    • 使用场景
      • 1、一个系统不依赖于产品线实例如何被创建、组合和表达的细节。
      • 2、系统中有多于一个的产品线,而每次只使用其中某一产品线。
      • 3、一个产品线(或是一组没有任何关系的对象)拥有相同的约束。
    • 优点:具体类的创建实例过程与客户端分离,客户端通过工厂的抽象接口操纵实例,客户端并不知道具体的实现是谁。
    • 缺点:增加新的产品族则也需要修改抽象工厂和所有的具体工厂。

4、总结对比

  • 简单工厂模式:单一产品线固定产品;一个工厂类,无抽象工厂类
  • 工厂模式:单一产品线可延伸产品(添加产品,只需添加IProduct的新产品实现类即可);一个抽象工厂类,所有产品共用一个工厂类
  • 抽象工厂模式:固定多产品线可延伸产品(添加产品,需添加IProduct的新产品实现类以及新产品的工厂类);一个抽象工厂类,每一个产品都有一个工厂类

你可能感兴趣的:(设计模式 ~ 工厂模式)