设计模式 ~ 工厂模式
2021-11-10 本文已影响0人
BTPJ
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<String>) {
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 <T : IPush> createPush(clazz: Class<T>): T
}
- 原来的工厂类继承抽象工厂类利用反射来初始化各产品对象
/**
* @author LTP 2021/11/10
*/
object PushFactory : AbsPushFactory() {
override fun <T : IPush> createPush(clazz: Class<T>): 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<String>) {
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<String>) {
// 小米工厂
val miFactory = MiFactory()
miFactory.createPush().push()
miFactory.createSend().send()
// 华为工厂
val huaWeiFactory = HuaWeiFactory()
huaWeiFactory.createPush().push()
huaWeiFactory.createSend().send()
}
}
}
执行结果:
小米手机使用小米推送
小米手机发送小米短信
华为手机使用华为推送
华为手机发送华为短信
-
使用场景与优缺点
-
使用场景:
- 1、一个系统不依赖于产品线实例如何被创建、组合和表达的细节。
- 2、系统中有多于一个的产品线,而每次只使用其中某一产品线。
- 3、一个产品线(或是一组没有任何关系的对象)拥有相同的约束。
- 优点:具体类的创建实例过程与客户端分离,客户端通过工厂的抽象接口操纵实例,客户端并不知道具体的实现是谁。
- 缺点:增加新的产品族则也需要修改抽象工厂和所有的具体工厂。
-
使用场景:
4、总结对比
- 简单工厂模式:单一产品线固定产品;一个工厂类,无抽象工厂类
- 工厂模式:单一产品线可延伸产品(添加产品,只需添加IProduct的新产品实现类即可);一个抽象工厂类,所有产品共用一个工厂类
- 抽象工厂模式:固定多产品线可延伸产品(添加产品,需添加IProduct的新产品实现类以及新产品的工厂类);一个抽象工厂类,每一个产品都有一个工厂类