Java设计模式:享元模式的介绍及代码演示

130 阅读4分钟

享元模式介绍

享元模式属于结构型模式,享是共享的意思,元是元素的意思,享元则表示将元素共享。享元模式的目的是通过共享已经创建的对象,来减少新对象的创建,节省内存开销,提高程序的性能。打个比方说,现在大部分城市都有共享电动车,通过这种共享出行的方式,节省了个人对私有电动车的资金投入,对于个人来说,这很显然节省了财产的消耗,并且由于减少了私有电动车的数量,环境的污染问题也得以减轻。

image.png

上面这张图中展示了四个人使用共享电动车,当所有的共享电动车都被使用时,只能等待新共享电动车的到来,如果已经存在闲置的共享电动车,则直接使用即可。这个例子主要说明,在程序中,如果一个对象已经存在,并且当前没有被占用或可以被使用,就没有必要再去创建一个新的对象,直接使用已经存在的对象即可。

享元模式示例代码

现在要用代码实现多人骑共享电动车的功能,当有人需要共享电动车时,则为其创建一个新的共享电动车,骑行结束并归还后,其他人则可以继续使用,否则,其他人必要也要等待新的共享电动车。在这个示例中,需要一个抽象享元类表示共享电动车,在共享电动车具体类中,实现骑车、还车、获取共享电动车状态及牌照的方法。其次需要一个享元工厂,实现对已经归还的电动车进行重新分配,如果已存在的所有电动车,都被使用,则为用户创建新的电动车。

创建抽象享元

/**
 * 共享电动车抽象
 */
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);
	}
}

享元类中,定义了骑车、还车的方法,当一辆电动车被骑行时,除非当前使用者将其归还,否则其他用户则无法获取这辆电动车,骑车和归还操作会修改共享电动车的状态,isStatetrue时,其他用户无法使用,否则相反。

创建享元工厂

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也就是状态=空闲中的电动车对象,减少了对象的创建。

测试用例运行结果:

image.png

可以看到创建的共享电动车对象的数量只有两个。至此,就实现了享元模式的案例搭建。

总结

如果程序中存在频繁创建相同对象的情况,可以考虑使用享元模式,从而降低内存消耗。通过享元模式,将对象的获取交给享元工厂,在非必要的情况下,直接返回给客户端已存在的对象即可,省去了对象的创建和销毁的过程。但是需要注意的是,享元模式通常通过一个状态去控制是否创建新的对象,这就导致在多线程的情况下,如果处理不当,可能会引发线程安全问题。