Follow treslines by email clicking Here!

Wednesday, August 20, 2014

Programming Design Pattern - Flyweight Pattern Applied - Best Practise

Hi there!

Today i'm gonna show the flyweight design pattern in action. The flyweight design pattern is a very useful programming design pattern while dealing with a lot of tiny, re-usable objects.

I'm assuming here you already know the concepts and i'll be focusing on practise. The example i will provide is a nice way to show it how it could looks like. You can always come back here, take it, adapt it and use it in your applictions as you may need. So be sure you bookmark it or join the group here on the right side of this post subscribing it.

First of all, let's take a look at the UML diagram of it. After that we will take the analogy for our example.

The UML Diagram of the Flyweight Pattern


Pay close attention, because once you understand that, everything will become clear and simple to understand. That's the reason I'm putting always the UML first. That way you'll get an eye for it with the time.



The example

In our example we will see, how we could use the flyweight pattern while dealing with lots of digits. Imagine you are writing a huge text file with a single big prime number. (memory issue) This could be a document with a few pages. All you need are digits to write the big prime number in it. So, you may create an object for every single digit, or you may create only 10 (0-9) and re-use it in the whole document. That's what we will do here. Pay close attention. Imagine how many other scenarios like this you may have in your applications. 

The Flyweights

Imagine that those flyweights bellow are reusable classes like the numbers 0-9. If you want to write a text or equation, you'll be able to reuse it instead of creating a new object, every time you write a digit.

public interface FlyweightField {
    public String getValue();
}
public class One implements FlyweightField {
    @Override
    public String getValue() {return " 1 ";}
}
public class Two implements FlyweightField {
    @Override
    public String getValue() {return " 2 ";}
}
public class Three implements FlyweightField {
    @Override
    public String getValue() {return " 3 ";}
}
public class Four implements FlyweightField {
    @Override
    public String getValue() {return " 4 ";}
}
public class Five implements FlyweightField {
    @Override
    public String getValue() {return " 5 ";}
}
public class Six implements FlyweightField {
    @Override
    public String getValue() {return " 6 ";}
}
public class Seven implements FlyweightField {
    @Override
    public String getValue() {return " 7 ";}
}
public class Eight implements FlyweightField {
    @Override
    public String getValue() {return " 8 ";}
}
public class Nine implements FlyweightField {
    @Override
    public String getValue() {return " 9 ";}
}

The number types

That's the class which represents the types we just defined above. It will be used in the FlyweightFactory bellow.

public enum FieldType {_1,_2,_3,_4,_5,_6,_7,_8,_9;}

public class FlyweightFieldFactory {
    private static FlyweightFieldFactory INSTANCE =  new FlyweightFieldFactory();
    private Map < FieldType, FlyweightField > fields =  new HashMap < FieldType, FlyweightField > ( );
    private FlyweightFieldFactory(){/*SINGLETON*/
        fields.put(FieldType._1, new One());
        fields.put(FieldType._2, new Two());
        fields.put(FieldType._3, new Three());
        fields.put(FieldType._4, new Four());
        fields.put(FieldType._5, new Five());
        fields.put(FieldType._6, new Six());
        fields.put(FieldType._7, new Seven());
        fields.put(FieldType._8, new Eight());
        fields.put(FieldType._9, new Nine());
    }
    public static FlyweightFieldFactory instance(){return INSTANCE;}
    public FlyweightField get(FieldType type){
        return fields.get(type);
    }
}

Testing it

Finally the test. Here we can see a possible usage of it. The interesting thing is the fact that we are reusing the same instances instead of creating new objects.

public class Client {
    public static void main(String[] args) {
        FlyweightField one1 = FlyweightFieldFactory.instance().get(FieldType._1);
        FlyweightField one2 = FlyweightFieldFactory.instance().get(FieldType._1);
        FlyweightField one3 = FlyweightFieldFactory.instance().get(FieldType._1);
        FlyweightField two1 = FlyweightFieldFactory.instance().get(FieldType._2);
        FlyweightField two2 = FlyweightFieldFactory.instance().get(FieldType._3);
        FlyweightField five1 = FlyweightFieldFactory.instance().get(FieldType._5);
        FlyweightField nine1 = FlyweightFieldFactory.instance().get(FieldType._9);
        System.out.println(one1.getValue());
        System.out.println(one2.getValue());
        System.out.println(one3.getValue());
        System.out.println(two1.getValue());
        System.out.println(two2.getValue());
        System.out.println(five1.getValue());
        System.out.println(nine1.getValue());
    }
}

That's all. Hope you like it!

2 comments:

  1. Hello,

    The get(...) function should instantiate the flyweight members, not the constructor. That way we can optimize the usage of memory. Only the asked members should be initialized. For example if we doesn't need nine1, than in Map there is no value for the key FieldType._9.

    Br,
    Márton

    ReplyDelete
    Replies
    1. Hi Márton, That's a nice improvement! In fact this would be true, if we assume that not all objects would be used at runtime.

      At the time i wrote this post, i was thinking about the alphabet and thinking of increasing application speed. Imagine that every alphabet object would be complex and time consuming while creating it (could be, just imagine it) and imagine that a text writer would for sure use all letter of the alphabet while writing something. In this case, it would be nice if i just lose time once, load everything into memory and from now on, just get the instances i need as the client requests it.

      I think that the pattern are not written in "stones" and could be adapted from case to case as long as it preserves its essence. But i agree with you! in the case we would not need nine and the creation wouldn't be complex and time consuming, then yes.

      Delete