享元模式介绍
享元模式属于结构型模式,享是共享的意思,元是元素的意思,享元则表示将元素共享。享元模式的目的是通过共享已经创建的对象,来减少新对象的创建,节省内存开销,提高程序的性能。打个比方说,现在大部分城市都有共享电动车,通过这种共享出行的方式,节省了个人对私有电动车的资金投入,对于个人来说,这很显然节省了财产的消耗,并且由于减少了私有电动车的数量,环境的污染问题也得以减轻。
上面这张图中展示了四个人使用共享电动车,当所有的共享电动车都被使用时,只能等待新共享电动车的到来,如果已经存在闲置的共享电动车,则直接使用即可。这个例子主要说明,在程序中,如果一个对象已经存在,并且当前没有被占用或可以被使用,就没有必要再去创建一个新的对象,直接使用已经存在的对象即可。
享元模式示例代码
现在要用代码实现多人骑共享电动车的功能,当有人需要共享电动车时,则为其创建一个新的共享电动车,骑行结束并归还后,其他人则可以继续使用,否则,其他人必要也要等待新的共享电动车。在这个示例中,需要一个抽象享元类表示共享电动车,在共享电动车具体类中,实现骑车、还车、获取共享电动车状态及牌照的方法。其次需要一个享元工厂,实现对已经归还的电动车进行重新分配,如果已存在的所有电动车,都被使用,则为用户创建新的电动车。
创建抽象享元
/**
* 共享电动车抽象
*/
public interface ElectricBicycleAbstract {
//骑车抽象方法
void cycling();
//还车抽象方法
void returnBicycle();
//电动车状态
boolean isState();
//车牌号
String getPlate();
}
创建具体享元
/**
* 共享电动车具体类
*/
public class ElectricBicycle implements ElectricBicycleAbstract{
//共享电动车牌照
private String plate;
//状态: true-骑行中、false-空闲中
private boolean state;
public ElectricBicycle(String plate) {
this.plate = plate;
}
@Override
public boolean isState() {
return state;
}
@Override
public String getPlate() {
return plate;
}
/**
* 骑车方法
*/
@Override
public void cycling() {
this.state = true;
System.out.println("共享单车已被骑走,车牌号:"+this.plate);
}
/**
* 还车方法
*/
@Override
public void returnBicycle() {
this.state = false;
System.out.println("共享单车已归还,车牌号:"+this.plate);
}
}
享元类中,定义了骑车、还车的方法,当一辆电动车被骑行时,除非当前使用者将其归还,否则其他用户则无法获取这辆电动车,骑车和归还操作会修改共享电动车的状态,isState
为true
时,其他用户无法使用,否则相反。
创建享元工厂
public class CyclingFactory {
private static List<ElectricBicycleAbstract> electricBicycles = new ArrayList<>();
public static ElectricBicycleAbstract getElectricBicycle() {
if(electricBicycles.size()>0) {
for(ElectricBicycleAbstract e : electricBicycles) {
if(!e.isState()) {
return e;
}
}
ElectricBicycleAbstract electricBicycle = new ElectricBicycle("ABC"+System.currentTimeMillis());
electricBicycles.add(electricBicycle);
return electricBicycle;
}else {
electricBicycles.add(new ElectricBicycle("ABC"+System.currentTimeMillis()));
return electricBicycles.get(0);
}
}
public static void printElectricBicycles(){
System.out.println("创建的共享电动车的数量:"+electricBicycles.size());
electricBicycles.forEach(e -> {
System.out.println("车牌号:"+e.getPlate());
});
}
}
享元工厂包含一个静态的集合属性electricBicycles
,存储了已经被创建的电动车对象,当调用getElectricBicycle()
方法时,会为用户提供一辆电动车,如果已存在空闲状态的电动车,则直接返回给用户,否则为用户创建一辆新的电动车对象。printElectricBicycles()
方法打印了已存在的电动车数量以及它们的牌照号码。
测试享元模式
public class test_01 {
public static void main(String[] args) throws InterruptedException {
//骑走一辆车
ElectricBicycleAbstract electricBicycle = CyclingFactory.getElectricBicycle();
electricBicycle.cycling();
Thread.sleep(500);
//骑走一辆车并在结束后归还
ElectricBicycleAbstract electricBicycle1 = CyclingFactory.getElectricBicycle();
electricBicycle1.cycling();
electricBicycle1.returnBicycle();
Thread.sleep(500);
//骑走一辆车
ElectricBicycleAbstract electricBicycle2 = CyclingFactory.getElectricBicycle();
electricBicycle2.cycling();
CyclingFactory.printElectricBicycles();
}
}
上面的测试用例代码,从享元工厂对象中获取了三次共享电动车对象,但是共享电动车对象只被创建了两次,因为在第二次使用电动车对象时,调用了electricBicycle1.returnBicycle()
方法将电动车归还了。所以在第三次获取电动车对象时,享元工厂直接返回了这个state = false
也就是状态=空闲中
的电动车对象,减少了对象的创建。
测试用例运行结果:
可以看到创建的共享电动车对象的数量只有两个。至此,就实现了享元模式的案例搭建。
总结
如果程序中存在频繁创建相同对象的情况,可以考虑使用享元模式,从而降低内存消耗。通过享元模式,将对象的获取交给享元工厂,在非必要的情况下,直接返回给客户端已存在的对象即可,省去了对象的创建和销毁的过程。但是需要注意的是,享元模式通常通过一个状态去控制是否创建新的对象,这就导致在多线程的情况下,如果处理不当,可能会引发线程安全问题。