关于设计模式很对开发者都知道很重要,但陆陆续续学习过很多次,但学过的设计模式也基本忘了差不多,能记住的还是之前使用的几个基本的,现在借此机会将23 中设计模式完整的梳理学习下,Java设计模式分类:
-
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
-
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
-
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式
本篇所有的实例代码和uml图地址:JavaDesignModule
1、Factory Method模式
- 简介:用Template Method的模式来构建生成实例的工厂,这就是工厂方法模式;
Factory Method模式原理来自意见产品的生产过程,从定义上的理解,将某一类事物按照面向对象的思想抽取成产品类,然后创建对应的工厂按照固定的模式创建相应的产品,相当于工厂里的产品生产线,一般使用工厂模式时都伴随着相似功能的类,这里的工厂模式也主要是根据条件创建正确的类;
- 设计模式的意义
- 工厂模式实现了对所有产品创建的管理,将产品和具体使用产品的类解耦
- 利于程序的扩展,有新添加产品时,只需要分别实现对应的产品类和工厂类即可
- 功能角色
- Product:抽象的产品类,内部定义产品的功能属性和方法;
- ObjectProduct:具体实现的产品类,针对具体的产品实现具体的功能;
- ProductFactory:抽象工厂类,定义创建产品的抽象方法;
- ObjectProductFactory:实现抽象工厂类,重写抽象方法根据设定的条件创建具体的产品;
- 使用
- 创建抽象产品类,并实现具体的产品和方法
interface Product {
fun action()
}
class Car(val name : String) : Product {
// 具体的产品类
override fun action() {
Log.e("Car -------- ","$name 是私家车!自己驾驶!")
}
}
- 创建产品工厂接口,并创建实现类
interface ProductFactory {
fun createProduct(name: String):Product //创建Product抽象方法
}
open class CarFactory : ProductFactory {
// 具体的工厂类
override fun createProduct(name: String): Product {
return Car(name)
}
}
- 使用工厂模式
val car = CarFactory().createProduct("Audi") //创建具体工厂类,并调用方法创建产品
car.action()
-
意义
工厂模式利用抽象产品的转型和统一管理产品的创建,将所有的实际产品和使用这些产品的代码解耦,有利于代码的扩展和维护 -
使用场景
- 针对某个抽象产品有多种实现时,可以使用工厂方法分别实现不同的产品类,然后再工厂中按需求创建产品;
2、Abstract Factory模式
-
简介
上面的工厂方法模式只是只针对单一类的产品,而对于多个产品时,如果继续使用工厂模式则势必要工厂类,这违背了开闭原则,此时需要使用抽象工厂模式,将工厂抽象出来,在工厂接口中定义多个产品的生产方法,然后让每个具体的工厂分别生产自己对应的一个或多个产品,从而形成不同的工厂群和各自产品线的形式; -
使用实例
- 定义两个产品Computer和Phone
abstract class Computer{
abstract fun action()
}
abstract class Phone(var name: String = "Phone") {
abstract fun call(number : String)
}
- 目前分别有两家工厂Green和Red生产,现在实现它们各自对应的产品类
class ComputerGreen : Computer() {
// 电脑
override fun action() {
System.out.println(" Action by Green Computer !")
}
}
class PhoneGreen : Phone() {
// 手机
override fun call(number: String) {
System.out.println(" Call $number by Green Phone !")
}
}
class ComputerRed : Computer() {
override fun action() {
System.out.println(" Action by Red Computer !")
}
}
class PhoneRed : Phone() {
override fun call(number: String) {
System.out.println(" Call $number by Red Phone !")
}
}
- 创建工厂接口,声明创建两个产品的方法
interface Factory {
fun createComputer() : Computer//生产电脑
fun createPhone() : Phone // 生产手机
}
- 实现两个各自的工厂类,分别创建自己的产品
class FactoryGreen : Factory {
override fun createComputer(): Computer {
return ComputerGreen() //生产Green电脑
}
override fun createPhone(): Phone {
return PhoneGreen() //生产Green手机
}
}
class FactoryRed : Factory {
override fun createComputer(): Computer {
return ComputerRed() //生产Red电脑
}
override fun createPhone(): Phone {
return PhoneRed() //生产Red手机
}
}
- 使用抽象工厂
val factoryGreen = FactoryGreen() // 创建Green工厂
factoryGreen.createComputer()
factoryGreen.createComputer()
val factoryRed = FactoryRed() // 创建Red工厂
factoryRed.createComputer()
factoryRed.createComputer()
- 意义:在工厂模式的基础上将工厂也抽象出来,这样可以实现多个工厂和多个产品的存在,当增加工厂个产品时直接创建其扩展类即可,无需修改原来的代码
- 使用场景:针对多种产品和多个分类时,可以使用抽象工厂模式统一管理所有产品
3、Singleton模式
-
简介
单例模式是开发中经常使用的基本模式,尤其在一些工具类或框架的初始化中,如:Glide、EventBus等,它的最主要特性就是确保一般情况下程序中只有一个实例; -
功能角色
-
使用实例
- 双重判断方式提供单例
class Singleton private constructor() {
companion object {
var singleton: Singleton? = null
fun getIntance(): Singleton {
if (singleton == null) {
synchronized(Singleton::class.java) {
singleton = Singleton()
}
}
return singleton!!
}
}
}
- 静态内部类方式
class SingletonInner private constructor() {
class SingleHolder {
companion object {
val singletonInner = SingletonInner()
}
}
}
- 使用单例模式
val single = Singleton.getIntance()
val singleInner = SingletonInner.SingleHolder.singletonInner
- 意义:对于经常需要使用但每次需要获取的对象,或初始化比较复杂的对象使用单例提供,节省获取或初始化的时间;
- 使用场景:想确保程序中只存在一个实例存在;
4、Builder模式
- 简介
Builder设计模式是很多人第一个接触的设计模式,就基本的Dialog就是使用Builder完成初始化,它利用在创建实例前使用Builder设置和保存配置的方式,极大的丰富了对象的使用场景和配置,而且使用中形成了链式调用;
-
功能角色
-
使用实例:参见AlertDialog的使用
-
意义:简化并统一对象的初始化过程,丰富对象的使用场景
-
使用场景
对于某个功能基本使用相同,但场景变化非常多时可以使用Builder模式,将具体和功能和变换的配置解耦;
5、Prototype模式
-
简介
原型模式,从名称的中就能大概读出他的意思,它是利用已有的对象直接克隆出新对象,相当于本身的复制版,从而避免一系列的初始化和创建工作,并且可以保持和现有对象完全一样的数据,对于原型本身需要具有调用clone()方法的能力,一般实现Cloneable接口即可; -
功能角色
- Prototype:原型接口,继承Cloneable接口
- PrototypeImpl:原型接口的实现类,也是克隆新对象的原始标本
- 使用实例
- 创建类实现Cloneable接口,在具体的类中调用clone()方法克隆对象
open class BaseProduct : Cloneable {
var name: String? = null
var price = 0
}
class CarProduct : BaseProduct(){
var coclor = "红色"
fun createClone(): CarProduct {
// 提供克隆方法
return super.clone() as CarProduct // 克隆并转换对象
}
}
- 对于对象嵌套的原型,即需要克隆的队像中持有别的对象;
class FoodProduct(var food: Food) : BaseProduct(){
fun createClone(): FoodProduct {
val product = super.clone() as FoodProduct
product.food = food.createClone()// 内部存储的对象也需要克隆并赋值
return product
}
}
- 上面代码中的FoodProduct中保存了Food对象,在克隆时如果要确保对象数据一致,就必须让food对象也克隆一份,所以Food对象也要实现Cloneable接口
open class Food(
var price: Int = 0,
var shop: String = "Shop"
) : Cloneable{
//因为浅复制的原因,Food也要实现Cloneable并且提供复制方法
fun createClone(): Food {
return super.clone() as Food
}
}
- 使用原型模式
val car = CarProduct()
car.name = "Audi"
car.price = 10000
val cerClone = car.createClone() // 克隆对象
Log.e("Car Name ---",cerClone.name)
Log.e("Car Price ---",cerClone.price.toString())
Log.e("Car Color ---",cerClone.coclor)
- 意义:避免对象的创建,而且可以复制出一份和当前对象数据一致的副本
6、Adapter模式
- 简介
对于适配器我们接触做多的就是电源适配器,对于我们身边的电源一般都提供的是220V交流电,但不同的电器设备所需的电压不同,那如何让它们正常使用呢?这就需要适配器的存在,它可以将200V的电压转换为各自需要的电压,而且不同的国家之间提供的电源也不同,那么经常出差的人员可能就会配备多种不同的适配器,但它们的作用只有一个将现有不可直接使用的转换为可用的;
同样的道理也适应在程序中,如果给你一个写好的工具类,需要将它使用在其他程序上,当然如果能直接使用最好,如果不能就需要在二者之间构建适配器
- 功能角色
- Target:创建抽象接口,在接口声明目标要调用的方法
- Adaptee:本来存在的工具类,即想要适配后调用的类
- Ad