设计模式--享元模式【结构型模式】
设计模式的分类
我们都知道有 23 种设计模式,这 23 种设计模式可分为如下三类:
- 创建型模式(5 种):单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式。
- 结构型模式(7 种):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
- 行为型模式(11 种):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
设计模式系列文章传送门
设计模式的 7 大原则
设计模式–单例模式【创建型模式】
设计模式–工厂方法模式【创建型模式】
设计模式–抽象工厂模式【创建型模式】
设计模式–建造者模式【创建型模式】
设计模式–原型模式【创建型模式】
设计模式–适配器模式【结构型模式】
设计模式–装饰器模式【结构型模式】
设计模式–代理模式【结构型模式】
设计模式–外观模式(门面模式)【结构型模式】
设计模式–桥接模式【结构型模式】
设计模式–组合模式【结构型模式】
什么是享元模式
享元模式使用优化系统性能的设计模式,享元模式的核心在于一个“享”字,也就是共享的意思,享元模式主要通过共享对象来减少系统中对象的数量,享元模式将对象分为内部状态和外部状态,内部状态的对象不会变化,外部对象会发生变化,享元模式本质就是缓存内部状态的共享对象,降低内存消耗。
享元模式的组成部分
- 抽象享元部分:享元对象抽象类或者接口,并定义出享元对象的外部状态和内部状态的的方法。
- 具体享元部分:实现抽象享元类或者接口,并实现了中的方法,简单来说具体享元部分就是可以被共享的对象。
- 享元工厂:负责创建和管理享元对象,维护了一个享元对象的缓存池,客户端请求获取享元对象时候,享元工厂会先检查缓存池中是否有相同的内部状态的享元对象,如果存在就直接返回,否则创建一个新的享元对象返回,同时也会把这个新创建的享元对象加入到缓存池,一般会使用一个 Map 存储已经创建的享元对象。
享元模式案例演示
我们再次以家用小汽车做为享元模式的演示对象,汽车就是一个享元对象,我们知道同样一款汽车会有不同颜色、不同续航里程,客户端在获取小汽车对象的时候,完全相同属性的小汽车对象就可以看做是一个内部状态的享元对象,可以共享使用。
XiaoMiCar(抽象享元部分)
我们定义 XiaoMiCar 为抽象享元部分,代码如下:
public class XiaoMiCar {
//颜色
public String color;
//续航
public String batteryLife;
public XiaoMiCar(String color, String batteryLife) {
this.color = color;
this.batteryLife = batteryLife;
}
public void xiaoMiCar() {
System.out.println("当前款小米汽车颜色:" + color + ",续航:" + batteryLife);
}
}
XiaoMiSu7Car(具体享元部分)
我们定义 XiaoMiSu7Car 为具体享元部分,代码如下:
public class XiaoMiSu7Car extends XiaoMiCar {
public XiaoMiSu7Car(String color, String batteryLife) {
super(color, batteryLife);
}
@Override
public void xiaoMiCar() {
System.out.println("当前款小米su7汽车颜色:" + color + ",续航:" + batteryLife);
}
}
XiaoMiYu7Car(具体享元部分)
我们定义 XiaoMiYu7Car 为具体享元部分,代码如下:
public class XiaoMiYu7Car extends XiaoMiCar {
public XiaoMiYu7Car(String color, String batteryLife) {
super(color, batteryLife);
}
@Override
public void xiaoMiCar() {
System.out.println("当前款小米yu7汽车颜色:" + color + ",续航:" + batteryLife);
}
}
XiaoMiCarFactory(享元工厂)
我们定义 XiaoMiCarFactory 为享元工厂,内部有一个 Map 来做为缓存容器,并提供了一个方法来获取享元对象,代码如下:
public class XiaoMiCarFactory {
//享元工厂
public static Map<String, XiaoMiCar> carMap = new HashMap<>();
//维护享元对象
public static XiaoMiCar queryCar(String color, String batteryLife, String type) {
String carKey = color + "-" + batteryLife;
XiaoMiCar xiaoMiCar = carMap.get(carKey);
if (xiaoMiCar == null) {
System.out.println(carKey+"为空,需要生产该类型的车");
if ("yu7".equals(type)) {
xiaoMiCar = new XiaoMiYu7Car("海湾蓝", "700KM");
} else {
xiaoMiCar = new XiaoMiSu7Car("钻石黑", "500KM");
}
//加入缓存
carMap.put(carKey, xiaoMiCar);
return xiaoMiCar;
} else {
System.out.println(carKey+"车已经存在,可以直接使用");
return xiaoMiCar;
}
}
}
XiaoMiCarClient(客户端)
我们定义 XiaoMiCarClient 客户端,多次获取同一款车型,来看看享元模式的效果,代码如下:
public class XiaoMiCarClient {
public static void main(String[] args) {
//第一次获取 xiaoMiSu7Car
XiaoMiCar xiaoMiSu7Car = XiaoMiCarFactory.queryCar("钻石黑", "500KM", "su7");
xiaoMiSu7Car.xiaoMiCar();
//第一次获取 xiaoMiYu7Car
XiaoMiCar xiaoMiYu7Car = XiaoMiCarFactory.queryCar("海湾蓝", "700KM", "yu7");
xiaoMiYu7Car.xiaoMiCar();
//第二次获取 xiaoMiSu7Car
XiaoMiCar xiaoMiSu7Car2 = XiaoMiCarFactory.queryCar("钻石黑", "500KM", "su7");
xiaoMiSu7Car2.xiaoMiCar();
//第二次获取 xiaoMiYu7Car
XiaoMiCar xiaoMiYu7Car2 = XiaoMiCarFactory.queryCar("海湾蓝", "700KM", "yu7");
xiaoMiYu7Car2.xiaoMiCar();
}
}
执行结果如下:
钻石黑-500KM为空,需要生产该类型的车
当前款小米su7汽车颜色:钻石黑,续航:500KM
海湾蓝-700KM为空,需要生产该类型的车
当前款小米yu7汽车颜色:海湾蓝,续航:700KM
钻石黑-500KM车已经存在,可以直接使用
当前款小米su7汽车颜色:钻石黑,续航:500KM
海湾蓝-700KM车已经存在,可以直接使用
当前款小米yu7汽车颜色:海湾蓝,续航:700KM
从结果可以看出同一款小汽车第一次获取的时候都没有获取到,重新创建了对象,第二次获取的时候就直接从享元工厂的缓存中获取到了对象,结果符合预期。
享元模式的优缺点
优点:
- 对象共享之后,避免重复对象的重复创建,提高了内存使用率。
- 对象共享之后,避免了重复对象的创建过程,减少了开销,提高了程序的响应性能。
- 内部对象和外部对象的隔离降低了对象的耦合度,内部对象由享元模式维护,外部对象由客户端维护。
缺点:
- 增加了系统的复杂性,因为要区分内部对象和外部对象。
- 对研发人员有一定的技术要求,需要清晰的分清内部对象和外部对象。
享元模式的使用场景
- 业务场景中有大量的相似对象的时候,可以使用享元模式减少内存开销。
- 对象的创建开销较大的时候,可以使用享元模式来降低对象创建的开销。
总结:本篇简单分享享元模式的概念和使用方式,享元模式重点在一个“享”字,主要目的是共享内部对象,减少对象的创建与销毁,我们在业务研发的时候也会常常用到,希望可以帮助到不太熟悉享元模式的朋友。
如有不正确的地方欢迎各位指出纠正。