Flyweight Pattern

Pros

  • When you need a large amount of objects, so much so that memory is a concern, you can share commanalities with flyweights

Cons

  • Increases complexity and is only needed if memory is a problem

Example Explanation

  • Monster - An abstract class which the two concrete flyweights inherit from
  • FlyweightZombie - The FlyweightZombie is shared between all MonsterClients with the name "Zombie" so its state does not vary (intrinsic state)
  • FlyweightGoblin - The FlyweightGoblin is shared between all MonsterClients with the name "Goblin" so its state does not vary (intrinsic state)
  • MonsterFactory - Returns a concrete flyweight for a MonsterClient to use. If the concrete flyweight needed has already been created then it will not create a new one.
  • MonsterClient - Keeps track of a Monster's varying state (extrinsic state) while having a reference to a flyweight monster for state that does not vary.

[UML]

import java.lang.*;
import java.util.HashMap;
import java.util.Map;

class Main {
  public static void main(String[] args) {
    MonsterClient monsters [] = {
      new MonsterClient("Zombie", 3), 
      new MonsterClient("Zombie", 7),
      new MonsterClient("Zombie", 11),
      new MonsterClient("Goblin", 1), 
      new MonsterClient("Goblin", 15)
    };
    //Zombie created
    //Goblin created

    System.out.println( MonsterFactory.getTotalFlyweightSize()+" flyweight monsters" ); 
    //2 flyweight monsters

  }
}

abstract class Monster{

  String name;
  int maxLife;
  int baseAttack;

  public Monster(String name, int maxLife, int baseAttack){
    this.name = name;
    this.maxLife = maxLife;
    this.baseAttack = baseAttack;
    System.out.println(name+" created");
  }
  public abstract void move();
  public int getMaxLife(){ return maxLife; }
  public int getBaseAttack(){ return baseAttack; }
  public String getName(){ return name; }
}

class FlyweightGoblin extends Monster{
  public FlyweightGoblin(){
    super("Goblin", 30, 7);
  }
  @Override
  public void move(){
    System.out.println(name+" scampers..");
  }
}

class FlyweightZombie extends Monster{
  public FlyweightZombie(){
    super("Zombie", 50, 4);
  }
  @Override
  public void move(){
    System.out.println(name+" trudges..");
  }
}

class MonsterFactory{
  private static Map<String, Monster> flyweights = new HashMap<>();

  public static Monster getMonster(String name){
    if(flyweights.containsKey(name)){
      return flyweights.get(name);
    }
    Monster mon;

    switch(name)
    {
      case "Zombie":{ mon = new FlyweightZombie(); break;}
      case "Goblin":{ mon = new FlyweightGoblin(); break;}
      default: throw new IllegalArgumentException("No monster with that name.");
    }
    flyweights.put(name, mon);

    return mon;
  }
  public static int getTotalFlyweightSize(){ return flyweights.size(); }
}

class MonsterClient{
  int level;
  int currentLife;
  int bonusLevelAttack;
  Monster monster;

  public MonsterClient(String name, int level){
    this.monster = MonsterFactory.getMonster(name);
    this.level = level;
    this.currentLife = monster.getMaxLife();
    this.bonusLevelAttack = level * 3;
  }

  public int getAttack(){ return monster.getBaseAttack() + bonusLevelAttack; }
  public int getLevel(){ return level; }
  public int getLife(){ return currentLife; }
  public int getMaxLife(){ return monster.getMaxLife(); }
  public String getName(){ return monster.getName(); }
}

Extra Resources

http://www.oodesign.com/flyweight-pattern.html

results matching ""

    No results matching ""