Look at design patterns (XIX. Flyweight) from the king of glory

See design mode from the glory of the King (Flyweight)

I. Introduction

In the glory of the King's classic battle mode, the soldier is an integral part. By kill hero soldier can obtain the required experience needed to upgrade equipment and purchase money. Soldier soldier can be divided into remote and melee creeps, etc. depending on the type. In addition, the game red and blue camps camp soldier will be slightly different.

II. Mode motivation

You need to add the number of classes and objects in the system in many cases. When too many objects, will lead to high operational costs, bring performance degradation and other issues. Flyweight pattern is to solve this problem born. Flyweight achieve the same or similar objects shared by reuse techniques, each object has appeared in a corresponding logical object is, however, they share the same physical Flyweight object. Flyweight object instance stored objects may be referred Flyweight pool
when implementing the Flyweight Note two issues: first class Flyweight design, some objects in the system are not exactly the same, they are just similar, first these need to find common objects, these common package contents Flyweight category, can be set by an external application to different contents, without sharing in these Flyweight may share the same content is referred to as the internal state (Intrinsic state), and those contents can not be shared need to set the external environment is referred to as external states (Extrinsic state), the disparity between the internal state and external state, can be provided by various external state such that the same object may be Some have different characteristics, and the same internal state can be shared second question is located Flyweight objects, usually occurs in the factory pattern Flyweight object, we need to create a Flyweight factory responsible for maintaining a pool Flyweight Flyweight objects (Flyweight Pool) for storing the internal state of the same

III. Flyweight

Flyweight (Flyweight Pattern): Use sharing to support a large number of fine particles multiplexing object. System uses only a small number of objects, and these objects are very similar, a small change in state, the object may be achieved by multiplexing a plurality of times. Since Flyweight claim shared objects must be capable of fine particles of an object, so it is called lightweight mode, it is an object schema structure

Flyweight usage scenario
can be used in the following Flyweight where
■ a system has a large number of identical or similar objects, since the use of such a large number of objects, resulting in consuming a large amount of memory.
■ Most object state can be externalized, these external states can be reached object.
■ Use Flyweight Flyweight need to maintain a storage object Flyweight pool, and this takes resources, therefore, it should be worth using Flyweight only when used repeatedly Flyweight objects.

Flyweight design patterns involved are:
★ change package (package factory mode)
★ class open for extension but closed for modification

FIG generic class Flyweight

Role Flyweight involved:
Flyweight comprising the following roles:
the Flyweight (Flyweight abstract class)
abstract class declaration enjoy an interface that can accept and act on it by external state. Defines the specific metaclass common method of sharing abstract Flyweight class, these methods may provide internal data (internal state) Flyweight object to the outside, but can also be provided by these methods external data (external states)
ConcreteFlyweight (particularly Flyweight class)
specific Flyweight Flyweight abstract class implements an interface, which is referred to as a shared element object instances; in particular enjoy metaclass provides storage space for the internal state, the object must be specifically Flyweight can be shared, so it the state must be stored inside, that it is independent of the presence of their environment. Single mode may be combined to design specific embodiment Flyweight classes, provided only enjoy a particular object for each element sharing metaclass
UnsharedConcreteFlyweight (particularly a non-shared class Flyweight)
not enjoy all abstract subclass of the metaclass of the need to be shared, It can not be shared or non-shared subclass are designed specifically Flyweight class; can be created directly instantiated when a non-shared requires particular when shared object metaclasses; hierarchy in some Flyweight, particularly enjoy unshared DETAILED metaclass can also enjoy the element object as a child node
FlyweightFactory (Flyweight factory class)
Flyweight factory class for creating and managing shared element object; it Flyweight abstract class for programming, various types of specific objects stored Flyweight Flyweight in a pool, the pool Flyweight generally designed as a set of a stored key-value pair (set may be other types) may be combined factory design pattern; when a user requests a specific shared element object, factories Flyweight is stored in a new instance of a shared pool of created element instance or create (if not present), returns the newly created instance, and stores In the Flyweight pool.

享元模式优点:
⑴.享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份
⑵.享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享

享元模式缺点:
⑴.使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序逻辑复杂化
⑵.为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长

四.享元模式经典实例

享元模式经典类图见上图(・ω<)☆
创建Flyweight(抽象享元类)

package com.classmodule.flyweight;
/*
 * 创建抽象享元类
 */
public abstract class Flyweight {
    //内部状态
    public String intrinsic;
    //外部状态
    public String extrinsic;
    
    //要求享元角色必须接受外部状态
    public Flyweight(String extrinsic) {
        this.extrinsic = extrinsic;
    }
    
    //定义业务操作
    public abstract void operate(int extrinsic);
    
    public String getInstrinsic() {
        return intrinsic;
    }
    
    public void setIntrinsic(String _intrinsic) {
        this.intrinsic = _intrinsic;
    }
}

创建ConcreteFlyweight类(具体享元类)

package com.classmodule.flyweight;
/*
 * 创建ConcreteFlyweight类(具体享元类)
 */
public class ConcreteFlyweight extends Flyweight{
    //接受外部状态
    public ConcreteFlyweight(String extrinsic) {
        super(extrinsic);
    }
    
    //根据外部状态进行逻辑处理
    @Override
    public void operate(int extrinsic) {
        System.out.println("具体Flyweight:" + extrinsic);
    }
}

创建UnsharedConcreteFlyweight(非共享具体享元类)

package com.classmodule.flyweight;
/*
 * 非共享具体享元类
 */
public class UnsharedConcreteFlyweight extends Flyweight{
    public UnsharedConcreteFlyweight(String extrinsic) {
        super(extrinsic);
    }

    @Override
    public void operate(int extrinsic) {
        System.out.println("非共享的具体Flyweight:" + extrinsic);
    }
}

创建Flyweight类(享元工厂类)

package com.classmodule.flyweight;

import java.util.HashMap;
/*
 * 创建享元工厂类
 */
public class FlyweightFactory {
    //定义一个池容器
    private static HashMap<String,Flyweight> pool = new HashMap<>();
    
    //享元工厂
    public static Flyweight getFlyweight(String extrinsic) {
        Flyweight flyweight = null;
        
        if(pool.containsKey(extrinsic)) {//池中有该对象
            flyweight = pool.get(extrinsic);
            System.out.print("已有 " + extrinsic + "直接从池中取出--->");
        }else {
            //根据外部状态创建享元对象
            flyweight = new ConcreteFlyweight(extrinsic);
            //放入池中
            pool.put(extrinsic, flyweight);
            System.out.print("创建" + extrinsic + "并从池中取出---->");
        }
        return flyweight;
    }
}

创建Client类(测试类)

package com.practice.Client;

import com.classmodule.flyweight.Flyweight;
import com.classmodule.flyweight.FlyweightFactory;

public class Client {
    public static void main(String[] args) {
        int extrinsic = 22;
        
        Flyweight flyweightX = FlyweightFactory.getFlyweight("X");
        flyweightX.operate(++extrinsic);
    
        Flyweight flyweightY = FlyweightFactory.getFlyweight("Y");
        flyweightY.operate(++extrinsic);
        
        Flyweight flyweightZ = FlyweightFactory.getFlyweight("Z");
        flyweightZ.operate(++extrinsic);
        
        Flyweight flyweightReX = FlyweightFactory.getFlyweight("X");
        flyweightReX.operate(++extrinsic);
    }
}

运行结果:

结果分析:共享池中创建存储了X,Y,Z三个对象,当Client再次向享元工厂请求X对象时,享元工厂从共享池中返回已经存在的对象实例。

五.无外部状态享元类

小兵有远程兵和超级兵。同种类型的小兵类型描述应该是一样的。
设计类图

创建抽象类(Soldier类)
Soldier类是抽象享元类,声明了所有具体享元类共有的方法

package com.practice.Flyweight;
/*
 * 创建抽象类(Soldier类):声明所有具体享元类共有的方法
 */
public interface Soldier {
    public abstract void funcDescription(Camp belongCamp);
}

创建具体享元类(LongRangeSoldier类)
LongRangeSoldier类是具体享元类,它实现了在抽象享元类中声明的方法。在LongRangeSoldier中声明了属性type,实例化时给该type赋值,相同的LongRangeSoldier对象其type值一定相同,因此type是享元类LongRangeSoldier类中可共享的内部状态

package com.practice.Flyweight;
/*
 * 创建具体享元类
 * @param type 共享的内部状态,相同LongRangeSoldier对象,type值一定相同。
 */
public class LongRangeSoldier implements Soldier {
    private String type;
    
    public LongRangeSoldier(String _type) {
        this.type = _type;
    }
    
    public String getType() {
        return this.type;
    }
    
    @Override
    public void typeDescription() {
        System.out.println("小兵分类:远程兵,类型为:" + type);
    }

}

创建具体享元类(ShortRangeSoldier类)
ShortRangeSoldier类是具体享元类,它实现了在抽象享元类中声明的方法。在ShortRangeSoldier中声明了属性type,实例化时给该type赋值,相同的ShortRangeSoldier对象其type值一定相同,因此type是享元类ShortRangeSoldier类中可共享的内部状态

package com.practice.Flyweight;
/*
 * 创建具体享元类
 * @param type 共享的内部状态,相同ShortRangeSoldier对象,type值一定相同。
 */
public class ShortRangeSoldier implements Soldier {
    private String type;
    
    public ShortRangeSoldier(String _type) {
        this.type = _type;
    }
    
    public String getType() {
        return this.type;
    }
    
    @Override
    public void typeDescription() {
        System.out.println("小兵分类:近战兵,类型为:" + type);
    }
}

创建共享工厂类(SoldierFactory类)
SoldierFactory是享元工厂类,在SoldierFactory中定义了一个ArrayList类型soldier,用于存储多个具体享元对象,它是一个享元池,也可以使用HashMap实现,在SoldierFactory类中还提供了工厂方法getSoldierCategory(),用来根据所传入的参数返回享元池中的享元对象

package com.practice.Flyweight;

import java.util.ArrayList;
/*
 * 创建共享工厂类(SoldierFactory类)
 */
public class SoldierFactory {
    private ArrayList<Soldier> soldier = new ArrayList<>();
    private int totalSoldier = 0;
    public SoldierFactory() {
        Soldier s1 = new LongRangeSoldier("法师(使用魔法弹攻击敌人,属于魔法攻击)");
        soldier.add(s1);
        Soldier s2 = new ShortRangeSoldier("超级兵(使用机甲攻击敌人,属于物理攻击)");
        soldier.add(s2);
    }
    
    //获得小兵的类型
    public Soldier getSoldierCategory(String type) throws Exception {
        if(type.equals("法师")) {
            totalSoldier ++;
            return (Soldier)soldier.get(0);
        }else if(type.equals("超级兵")) {
            totalSoldier ++;
            return (Soldier)soldier.get(1);
        }else {
            throw new Exception();
        }
    }
    
    //获得小兵总数
    public int getSoldierCount() {
        return totalSoldier;
    }
    //获得小兵分类总数
    public int getSoldierType() {
        return soldier.size();
    }
}

创建客户测试类(Client类)

package com.practice.Client;

import com.practice.Flyweight.Soldier;
import com.practice.Flyweight.SoldierFactory;

public class Client {
    public static void main(String [] args) throws Exception {
        Soldier fx,fy,fz,fa,fb,fc;
        SoldierFactory factory = new SoldierFactory();
        
        fx = factory.getSoldierCategory("法师");
        fx.typeDescription();
        
        fy = factory.getSoldierCategory("超级兵");
        fy.typeDescription();
        
        fz = factory.getSoldierCategory("超级兵");
        fz.typeDescription();
        
        fa = factory.getSoldierCategory("超级兵");
        fa.typeDescription();
        
        fb = factory.getSoldierCategory("法师");
        fb.typeDescription();
        
        fc = factory.getSoldierCategory("法师");
        fc.typeDescription();
        
        System.out.println("小兵分类总数:" + factory.getSoldierType());
        System.out.println("小兵总数为:" + factory.getSoldierCount());   
    }
}

运行结果:

结果分析:在客户端代码中定义了6个Soldier对象,即享元对象,并且实例化了享元工厂SoldierFactory,通过SoldierFactory类中的工厂方法返回享元对象。调用了每一个享元对象的typeDescription()方法。Soldier类型的type是内部状态,可以共享,相同小兵类型其type一定相同

六.有外部状态的享元类

游戏存在里两个红、蓝两个阵营。小兵应该标识阵营
设计类图

创建抽象享元类(Soldier类)
Soldier类是抽象享元类,声明了所有具体享元类共有的方法

package com.practice.Flyweight;
/*
 * 创建抽象类(Soldier类):声明所有具体享元类共有的方法
 */
public interface Soldier {
    public abstract void funcDescription(Camp belongCamp);
}

创建外部状态(Camp)
用来标识小兵所属阵营

package com.practice.Flyweight;
/*
 *创建外部状态(Camp),用于标识小兵所属阵营
*/
public class Camp {
    private String belongCamp;
    
    public Camp(String _belongCamp) {
        this.belongCamp = _belongCamp;
    }
    
    public String getCamp() {
        return belongCamp;
    }
}

创建具体享元类(LongRangeSoldier类)

package com.practice.Flyweight;
/*
 * 创建具体享元类
 * @belongCamp接收外部状态
 */
public class LongRangeSoldier implements Soldier {
    private String type;
    
    public LongRangeSoldier(String _type) {
        this.type = _type;
    }
    
    public String getType() {
        return this.type;
    }

    @Override
    public void funcDescription(Camp belongCamp) {
        System.out.println("小兵分类:远程兵,类型为:" + type + ":" + belongCamp.getCamp());    
    }
}

创建具体享元类(ShortRangeSoldier类)

package com.practice.Flyweight;
/*
 * 创建具体享元类
 * @param belongCamp接受外部状态
 */
public class ShortRangeSoldier implements Soldier {
    private String type;
    
    public ShortRangeSoldier(String _type) {
        this.type = _type;
    }
    
    public String getType() {
        return this.type;
    }

    @Override
    public void funcDescription(Camp belongCamp) {
        System.out.println("小兵分类:近战兵,类型为:" + type + ":" + belongCamp.getCamp());
    }
}

创建享元工厂类(SoldierFactory类)

package com.practice.Flyweight;

import java.util.ArrayList;
/*
 * 创建共享工厂类(SoldierFactory类)
 */
public class SoldierFactory {
    private ArrayList<Soldier> soldier = new ArrayList<>();
    private int totalSoldier = 0;
    public SoldierFactory() {
        Soldier s1 = new LongRangeSoldier("法师(使用魔法弹攻击敌人,属于魔法攻击)");
        soldier.add(s1);
        Soldier s2 = new ShortRangeSoldier("超级兵(使用机甲攻击敌人,属于物理攻击)");
        soldier.add(s2);
    }
    
    //获得小兵的类型
    public Soldier getSoldierCategory(String type) throws Exception {
        if(type.equals("法师")) {
            totalSoldier ++;
            return (Soldier)soldier.get(0);
        }else if(type.equals("超级兵")) {
            totalSoldier ++;
            return (Soldier)soldier.get(1);
        }else {
            throw new Exception();
        }
    }
    
    //获得小兵总数
    public int getSoldierCount() {
        return totalSoldier;
    }
    //获得小兵分类总数
    public int getSoldierType() {
        return soldier.size();
    }
}

创建客户测试类(Client)

package com.practice.Client;

import com.practice.Flyweight.Camp;
import com.practice.Flyweight.Soldier;
import com.practice.Flyweight.SoldierFactory;

public class Client {
    public static void main(String [] args) throws Exception {
        SoldierFactory factory = new SoldierFactory();
        
        Soldier fx = factory.getSoldierCategory("法师");
        fx.funcDescription(new Camp("红方阵营"));
        
        Soldier fy = factory.getSoldierCategory("超级兵");
        fy.funcDescription(new Camp("红方阵营"));
        
        Soldier fz = factory.getSoldierCategory("超级兵");
        fz.funcDescription(new Camp("蓝方阵营"));
        
        Soldier fa = factory.getSoldierCategory("超级兵");
        fa.funcDescription(new Camp("红方阵营"));
        
        Soldier fb = factory.getSoldierCategory("法师");
        fb.funcDescription(new Camp("蓝方阵营"));
        
        Soldier fc = factory.getSoldierCategory("法师");
        fc.funcDescription(new Camp("蓝方阵营"));
        
        System.out.println("小兵分类总数:" + factory.getSoldierType());
        System.out.println("小兵总数为:" + factory.getSoldierCount());   
    }
}

运行结果:

结果分析:在Client中,在调用fx等享元对象的funcDescription()方法时,传入了一个Camp类型的对象,在该Camp对象中封装类所属阵营,作为小兵的外部状态

七.源代码下载

从王者荣耀看设计模式(享元模式)

Guess you like

Origin www.cnblogs.com/miaowulj/p/12171118.html