在软件中,通常会有很多相同的角色。比如五子棋,一场对局中会有多个五子棋,若是用普通方法,一个五子棋就一个对象实例,这样将消耗大量的系统资源。像这种情况就可以使用享元模式了
享元(Flyweight)模式的定义:运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
优点:
- 相同对象只要保存一份,这降低了系统中对象的数量,从而降低了系统中细粒度对象给内存带来的压力。
缺点:
- 为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。
- 读取享元模式的外部状态会使得运行时间稍微变长。
享元模式的结构与实现
结构:
- 抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
- 具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。
- 非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
- 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
实现:
实现场景:LOL中的小兵,小兵有三类:炮兵,远程兵,近战兵
package com.wly.DesignPatterns;
import java.util.HashMap;
import java.util.Map;
/**
* @program: StudyDome
* @author: yuanzhang
* @create: 2020-12-27 15:41
**/
public class FlyweightStudy {
public static void main(String[] args) {
DogfaceFactory factory = new DogfaceFactory();
//创建小兵
System.out.println("创建小兵----------------------------------");
Dogface dogface = factory.getDogface(DogfaceType.Artillery);
Dogface dogface1 = factory.getDogface(DogfaceType.LongRangeDogface);
Dogface dogface2 = factory.getDogface(DogfaceType.MeleeDogface);
//给小兵赋予状态
System.out.println("小兵完整的信息----------------------------");
DogfaceAttribute dogfaceAttribute = new DogfaceAttribute(DogfaceType.Artillery);
DogfaceAttribute dogfaceAttribute1 = new DogfaceAttribute(DogfaceType.LongRangeDogface);
DogfaceAttribute dogfaceAttribute2 = new DogfaceAttribute(DogfaceType.MeleeDogface);
dogface.state(dogfaceAttribute);
dogface1.state(dogfaceAttribute1);
dogface2.state(dogfaceAttribute2);
//远程兵被攻击损失30血
dogfaceAttribute1.setBloodVolume(dogfaceAttribute1.getBloodVolume()-30);
System.out.println("远程兵被攻击后的状态------------------------------");
dogface1.state(dogfaceAttribute1);
}
}
class DogfaceType{
public static String Artillery ="artillery";
public static String LongRangeDogface ="longRangeDogface";
public static String MeleeDogface ="meleeDogface";
}
/**
* @Annotation:非享元角色:血量、攻击距离
* @Author: yuanzhang
* @Date: 15:45
*/
class DogfaceAttribute{
private Long BloodVolume;
private Long StrikingDistance;
public DogfaceAttribute(String name){
switch (name){
case "artillery":
//炮兵属性
this.BloodVolume = 900L;
this.StrikingDistance = 400L;
break;
case "longRangeDogface":
//远程兵属性
this.BloodVolume = 500L;
this.StrikingDistance = 450L;
break;
case "meleeDogface":
//近战兵属性
this.BloodVolume = 700L;
this.StrikingDistance = 100L;
break;
default:
break;
}
}
public void setBloodVolume(Long bloodVolume) {
BloodVolume = bloodVolume;
}
public Long getBloodVolume() {
return BloodVolume;
}
public void setStrikingDistance(Long strikingDistance) {
StrikingDistance = strikingDistance;
}
public Long getStrikingDistance() {
return StrikingDistance;
}
}
/**
* @Annotation:抽象享元:小兵
* @Author: yuanzhang
* @Date: 17:13
*/
interface Dogface{
void state(DogfaceAttribute dogfaceAttribute);
}
/**
* @Annotation:具体享元:炮兵
* @Author: yuanzhang
* @Date: 17:13
*/
class Artillery implements Dogface{
private String name;
Artillery(String name){
this.name = name;
System.out.println("炮兵被创建");
}
@Override
public void state(DogfaceAttribute dogfaceAttribute) {
System.out.println(name+"(血量:"+dogfaceAttribute.getBloodVolume()+",攻击距离:"+dogfaceAttribute.getStrikingDistance()+")");
}
}
/**
* @Annotation:具体享元:远程兵
* @Author: yuanzhang
* @Date: 17:12
*/
class LongRangeDogface implements Dogface{
private String name;
LongRangeDogface(String name){
this.name = name;
System.out.println("远程兵被创建");
}
@Override
public void state(DogfaceAttribute dogfaceAttribute) {
System.out.println(name+"(血量:"+dogfaceAttribute.getBloodVolume()+",攻击距离:"+dogfaceAttribute.getStrikingDistance()+")");
}
}
/**
* @Annotation:具体享元:近战兵
* @Author: yuanzhang
* @Date: 17:12
*/
class MeleeDogface implements Dogface{
private String name;
MeleeDogface(String name){
this.name = name;
System.out.println("近战小兵被创建");
}
@Override
public void state(DogfaceAttribute dogfaceAttribute) {
System.out.println(name+"(血量:"+dogfaceAttribute.getBloodVolume()+",攻击距离:"+dogfaceAttribute.getStrikingDistance()+")");
}
}
/**
* @Annotation:享元工厂角色:兵工厂
* @Author: yuanzhang
* @Date: 17:11
*/
class DogfaceFactory{
private Map<String,Dogface> dogfaceMap = new HashMap<String,Dogface>();
public Dogface getDogface(String name){
Dogface dogface = dogfaceMap.get(name);
if (dogface==null){
DogfaceAttribute dogfaceAttribute = new DogfaceAttribute(name);
switch (name){
case "artillery":
dogface = new Artillery(name);
break;
case "longRangeDogface":
dogface = new LongRangeDogface(name);
break;
case "meleeDogface":
dogface = new MeleeDogface(name);
break;
default:
break;
}
dogfaceMap.put(name,dogface);
}
return dogface;
}
}
输出
创建小兵---------------------------------- 炮兵被创建 远程兵被创建 近战小兵被创建 小兵完整的信息---------------------------- artillery(血量:900,攻击距离:400) longRangeDogface(血量:500,攻击距离:450) meleeDogface(血量:700,攻击距离:100) 远程兵被攻击后的状态 longRangeDogface(血量:470,攻击距离:450)
这个例子不太恰当,非享元角色应为小兵的动态血量,以及位置。不应该是固有的初始血量,和固定的攻击距离。
所以再做个总结理解一下享元模式:
享元模式就是对一些重复的对象,抽出其变化的数据来作为非享元角色。根据非享元角色的数据来确定一个新的对象。这样就不需要重复创建相同的对象,只需要改变其变化的状态。