知识点十三:享元模式
一、概述
享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。它属于23种GOF设计模式的结构型设计模式 ,它提供了减少对象数量从而改善应用所需的对象结构的方式。
在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)(用于存储具有相同内部状态的享元对象),将对象放在享元池中重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
二、优缺点及使用场景
1、优点
- 它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
- 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
2、缺点
- 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
- 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
3、使用场景
- 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。
- 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中(细粒度对象)。
- 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。
三、模式中的角色及职责和实现方式
1、角色
- 抽象享元(Flyweight)角色:所有具体享元类的父类,规定一些需要实现的公共接口。
- 具体享元(ConcreteFlyweight)角色:具体的享元实现对象,必须是可共享的,需要封装享元对象的内部状态。
- 享元工厂(FlyweightFactory)角色:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口。
2、实现方式
享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
四、Java中的实现方式
Person.java
/**
* @Description: 抽象享元(Flyweight)角色 人
* @Author: Ling.D.S
* @Date: Created in 2018/11/22 14:58
*/
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Staff.java
/**
* @Description: 具体享元(ConcreteFlyweight)角色 员工
* @Author: Ling.D.S
* @Date: Created in 2018/11/22 15:01
*/
public class Staff extends Person {
private String number; //员工号
public Staff() {
super();
}
public Staff(String name, int age) {
super(name, age);
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
StaffFactory.java
/**
* @Description: 享元工厂(FlyweightFactory)角色
* @Author: Ling.D.S
* @Date: Created in 2018/11/22 15:05
*/
public class StaffFactory {
//我们希望通过员工号来找到员工
private Map<String,Staff> pool;//资源池
public StaffFactory() {
pool = new HashMap<String, Staff>();
}
public Staff getStaff(String number){
Staff staff = pool.get(number);
//如果staff为null则new一个空的
if(staff == null){
System.out.println("没有该员工,添加该员工");
staff = new Staff();
staff.setNumber(number);
pool.put(number,staff);
}
return staff;
}
}
MainClass.java
/**
* @Description: 有抽象享元角色的实现,客户端调用
* @Author: Ling.D.S
* @Date: Created in 2018/11/22 14:58
*/
public class MainClass {
public static void main(String[] args) {
//1.创建工厂
StaffFactory factory = new StaffFactory();
//2.从工厂取值
Staff staff1 = factory.getStaff("001");
Staff staff2 = factory.getStaff("002");
Staff staff3 = factory.getStaff("003");
System.out.println(staff1.getNumber());
System.out.println(staff2.getNumber());
System.out.println(staff3.getNumber());
System.out.println("==============");
//这时候资源池中就有员工123了,现在把"002"改为"001"看是不是同一个对象
staff2 = factory.getStaff("001");
if(staff1 == staff2){
System.out.println("是同一个对象");
}else{
System.out.println("不是同一个对象");
}
}
}
转载请注明原地址,宋德凌的博客:http://CoderOfSong.github.io 谢谢!