欢迎关注微信公众号:FSA全栈行动
一、前言
设计模式是软件工程中解决特定问题的一种指南,我们常说 Java 有 23 种设计模式,而多范式的 Kotlin 作为更好的 Java,拥有很多新的语言特性,在使用原本 Java 中常用的设计模式时,可github中文官网网页以有哪些方面的改良呢?
说明:本系列是本giti人对《Kotlin 核心编程》第 9 章 设计模式 的理解软件商店总结,ios是什么意思所以总结内容上会有些改动,另外,部分篇章个人觉得意义不大,所以没有在本系列中进行概括,有兴趣可自行查阅原书籍。
- 工厂模式
- 作用:隐藏对象实例的创建逻辑,而不需要暴露给客户端。
- 细分:简单工厂、工厂方法、抽象工厂。
二、改良简单工厂
- 例子:电脑厂商生反射机制产电脑(服务器、家用 PC)
- 重点:伴生对象、运算符重载(
invoke
)
/**
* 电脑接口
*
* @author GitLqr
*/
interface Computer {
val cpu: String
}
/**
* 电脑类
*
* @author GitLqr
*/
class PC(override val cpu: String = "Core") : Computer
class Server(override val cpu: String = "Xeon") : Computer
/**
* 电脑类型枚举
*
* @author GitLqr
*/
enum class ComputerType {
PC, SERVER
}
简单工厂,一般会使用单例模式(私有化构造器,强制通过类方python是什么意思法来使用),先来看 Java 版本:
/**
* 简单电脑工厂(Java版)
*
* @author GitLqr
*/
public static class ComputerFactory {
private ComputerFactory() {
}
public static Computer produce(ComputerType type) {
if (type == ComputerType.PC) {
return new PC();
} else if (type == ComputerType.SERVER) {
return new Server();
} else {
throw new IllegalArgumentException("没有其他类型的电脑了");
}
}
}
// 使用
Computer pc = ComputerFactory.produce(ComputerType.PC);
Computer server = ComputerFactory.produce(ComputerType.SERVER);
Kotlin 在语言层面就已经实现了单例(使用 object
关键字替代 class
),所以将上述代码改造成 Kotlin 版本:
/**
* 简单电脑工厂(Kotlin版)
*
* @author GitLqr
*/
object ComputerFactory {
fun produce(type: ComputerType): Computer {
return when (type) {
ComputerType.PC -> PC()
ComputerType.SERVER -> Server()
}
}
}
// 使用
val pc = ComputerFactory.produce(ComputerType.PC)
val server = ComputerFactory.produce(ComputerType.SERVER)
以上只不过是用 Kotlin 翻译了一遍 Java 代码,下面进入正题,从这个简单工厂的使用上,我们知道核心是让 ComputerFactory
根据不同的 ComputerType
参数来创建电脑实例ios下载,而这个 produce
方法名并不重要,结合 Kotlin 的运算符重载,可以进一步简化代码:
/**
* 简单工厂改良:重载 invoke 运算符
*
* @author GitLqr
*/
object ComputerFactory {
operator fun invoke(type: ComputerType): Computer {
return when (type) {
ComputerType.PC -> PC()
ComputerType.SERVER -> Server()
}
}
}
// 使用
val pc = ComputerFactory(ComputerType.PC)
val server = ComputerFactory(ComputerType.SERVER)
你python基础教程可能会觉得 ComputerFactory(Compugithub永久回家地址terType软件库蓝奏云.PC)
这样的代码也太奇github是干什么的怪了,更像是在创建一个工厂实例,如果能改成 Computer(ComputerType.PC)
这样的代码的话,才比较符合正常逻辑吧,没问题,只需要在 Computer
接口中搞一个静态工厂方法代替构造器就好了,先来看下 Jav软件a 版本:
/**
* 静态工厂方法(Java版)
*
* @author GitLqr
*/
interface Computer {
class Factory{ // 等同于 public static class Factory
public static Computer produce(ComputerType type){
if (type == ComputerType.PC) {
return new PC();
} else if (type == ComputerType.SERVER) {
return new Server();
} else {
throw new IllegalArgumentException("没有其他类型的电脑了");
}
}
}
...
}
// 使用
Computer pc = Computer.Factory.produce(ComputerType.PC);
Computer server = Computer.Factory.produce(ComputerType.SERVER);
将上面的 Java 代码翻译成 Kotlin 版本:
/**
* 静态工厂方法(Kotlin版)
*
* @author GitLqr
*/
interface Computer {
companion object Factory{
fun produce(type: ComputerType): Computer {
return when (type) {
ComputerType.PC -> PC()
ComputerType.SERVER -> Server()
}
}
}
...
}
// 使用
val pc = Computer.Factory.produce(ComputerType.PC)
val server = Computer.Factory.produce(ComputerType.SERVER)
注意:伴生对象名iOS称默认是
Cgiti轮胎ompanion
,可以自定义,但是不管指不指定名称,使用时都可以省略不写,所以上面的代码也可以这样Computer.produce(ComputerType.PC)
,但有一种github永久回家地址情况除外软件商店下载,如果是给伴生对象扩展属性或方法时,就必须写上伴生对象的自定义名称了。
我们知道,Kotlpython代码大全in 中伴生对象的名称是可以省略不写的的,结合运算符重载,上述代码可github中文官网网页以进一步简化为:
/**
* 静态工厂方法改良:重载【伴生对象】 invoke 运算符
*
* @author GitLqr
*/
interface Computer {
companion object {
operator fun invoke(type: ComputerType): Computer {
return when (type) {
ComputerType.PC -> PC()
ComputerType.SERVER -> Server()
}
}
}
...
}
// 使用
val pc = Computer(ComputerType.PC)
val server = Computer(ComputerType.SERVER)
三、改良抽象工厂
- 例子:电脑品牌厂商生产电脑
- 重点:Git内联函数(
inl软件测试ine
+reified
)
现在增加了品牌厂商的概念,比如 Dell、Asus 等,如果用简单工厂软件库模式,则需要再创建 n 个品牌厂商工厂类,比如 DellComputerFactory、AsusComputerFactory,品牌厂商众多,为了后续扩展,需要对工厂进行抽象:
/**
* 各品牌电脑
*
* @author GitLqr
*/
interface Computer
class Dell : Computer
class Asus : Computer
/**
* 各品牌厂商
*
* @author GitLqr
*/
abstract class AbstractFactory {
abstract fun produce(): Computer
}
class DellFactory : AbstractFactory() {
override fun produce() = Dell()
}
class AsusFactory : AbstractFactory() {
override fun produce() = Asus()
}
抽象工厂模式,一般会在抽象工厂类中提供一个根据 参数
获取具体工厂实例的方法,结合 Kotlin 的重载运算giti轮胎符特性,该方法可以这么写:
/**
* 抽象工厂:根据方法参数构建工厂实例
*
* @author GitLqr
*/
abstract class AbstractFactory {
abstract fun produce(): Computer
companion object {
operator fun invoke(type: String): AbstractFactory {
return when (type) {
"dell" -> DellFactory()
"asus" -> AsusFactory()
else -> throw IllegalArgumentException()
}
}
}
}
// 使用:
val factory = AbstractFactory("dell")
val computer = factory.produce()
注意:python怎么读该
参数
是什么东西并没有限制,可以是字符串、枚举、具体工厂实例等等,在《Kotlin 核心编程》中,案例使用的参数是传入具体工厂实例,我个人认为这样不妥,因为工厂模式的核心就是隐藏对象实例的创建逻辑,而不需要暴露给客户端
,所以这里我改python123平台登录用为字符串来做区分。
这里要思考一个问题,实软件工程际项目中使用字符串方式来区分工厂类型并不ios下载合理,因为会造成调用处硬编码的问题,改用枚举gitee会更加合适,但是枚举会增加类文件啊,那么有什么方案可以规避掉上述两种弊端呢?很简单,直接把具体 Computer
的类类型传进方法内做判断:
import java.lang.reflect.Type
/**
* 抽象工厂传参优化(Java反射包)
*
* @author GitLqr
*/
abstract class AbstractFactory {
abstract fun produce(): Computer
companion object {
operator fun invoke(type: Type): AbstractFactory {
return when (type) {
Dell::class -> DellFactory()
Asus::class -> AsusFactory()
else -> throw IllegalArgumentException()
}
}
}
}
// 使用
val factory = AbstractFactory(Dell::class.java)
val computer = factory.produce()
注意:在 Jgitiagithub是干什么的va 中,类类型对应是用
java.lang.reflect.Typios模拟器e
来表示github永久回家地址,一般通过类.class
这种方式来获取,对应到 Kotlin 的写法就是类::class.java
你应该注意到了,这个 Type
是 Java 反射包中的类,而 Kotlin 完全兼容 Java,自然可以使用 java.lang.reflect.Type
来表示类类型,软件商店下载不过,Kotlin 自身也有一套反射机制,可以使用 kotlin.reflpython可以做什么工作ect.KClass
来表示类类型,所以,使用 Ko软件技术专业tlin 反射 API 版本如下:
import kotlin.reflect.KClass
/**
* 抽象工厂传参优化(Kotlin反射包)
*
* @author GitLqr
*/
abstract class AbstractFactory {
abstract fun produce(): Computer
companion object {
// operator fun invoke(type: KClass<*>): AbstractFactory
operator fun invoke(type: KClass<out Computer>): AbstractFactory {
return when (type) {
Dell::class -> DellFactory()
Asus::class -> AsusFactory()
else -> throw IllegalArgumentException()
}
}
}
}
// 使用
val factory = AbstractFactory(Dell::class)
val computer = factory.produce()
注意:
KClass<*&gpython123平台登录t;
中的*
是一个通配符,表示接收任意类类型;而KClass<out Compython下载puter>
中使用了out
关键字,这是 Kotlin 中的泛型协变,表示只接收Computer
子类的类类型。
其实,通过 Absios鲁多多apptractFactory(Dell::class)
这种方式来获取具体工厂实例python下载已经够用了,但是使github开放私库用泛型还可以进一步简化代码,最终写法为:AbstractFactory<Dell>()
,是不是更加直观优雅?那么要怎么使用iOS泛型来改造上面的方法呢?要知道 Java 泛型是在 1.5 之后才有的,为了向后兼容python编程,泛型参数类型会在编译期被擦除(纯粹的github开放私库历史包袱 =_=),所以在 Java 中软件工程专业要获取一个泛型的参数类型是十分困难的,而 Kotlin 的内联函数(inline
)配合 reified
关键字,却可以做到具体化泛型参数类型,从而github是干什么的让获取 泛型参数类型 变得尤为简单:
/**
* 抽象工厂改良:根据泛型参数类型构建工厂实例(inline + reified 具体化泛型参数类型)
*
* @author GitLqr
*/
abstract class AbstractFactory {
abstract fun produce(): Computer
companion object {
inline operator fun <reified T : Computer> invoke(): AbstractFactory {
return when (T::class) { // 不使用 reified 的话,T::class 会报错
Dell::class -> DellFactory()
Asus::class -> AsusFactory()
else -> throw IllegalArgumentException()
}
}
}
}
// 使用
val factory = AbstractFactory<Dell>()
val computer = factory.produce()
四、补充
在 【二、改良简单工厂】 部分提到了伴生对象指定名称问题github永久回家地址, 这里做一下补充。假设 Computergitee 是由其他同事或第三方人员编写ios系统的,我ios15们不方便直接在其伴生对象中增加新功能,这时,可以使用 Kotlin 的扩展特性ios15,给伴生对象扩展方法,比如给 Computer 增加一个功能,通过 CPU 型号来判python可以做什么工作断电脑类型:
/**
* 伴生对象扩展方法(默认名称)
*
* @author GitLqr
*/
fun Computer.Companion.fromCPU(cpu: String): ComputerType? = when (cpu) {
"Core" -> ComputerType.PC
"Xeon" -> ComputerType.SERVER
else -> null
}
// 使用
val type = Computer.fromCPU(pc.cpu)
如果此时 Computer 中的伴生对象已经指定了名称为 Factory
,那么在给伴生对象扩展方法时就必须使用对应的伴生对象名称,而不是默软件商店认的 Companion
了:
interface Computer {
// 自定义伴生对象名称
companion object Factory { ... }
}
/**
* 伴生对象扩展方法(自定义名称)
*
* @author GitLqr
*/
fun Computer.Factory.fromCPU(cpu: String): ComputerType? = when (cpu) { ... }
// 使用
val type = Computer.fromCPU(pc.cpu)
结论:
- 扩展伴生对象方法时,如果伴生对象有自定义名称,则使用自定义名称进行软件库蓝奏云扩展。
- 无论伴生对象是否有自定义名称,调用时均可省略不写。
如果文章对您有所帮助, 请不吝点击关注一下我的微信公众号:FSA全栈行动, 这将是对我最大的激励. 公众号不python是什么意思仅有Android技术, 还有iOS, Python等文章, 可能有你想要了解的技能知识点哦~