DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Object Relational Behavioral Design Patterns in Java
  • Distribution Design Patterns in Java - Data Transfer Object (DTO) And Remote Facade Design Patterns
  • Context Object Design Pattern in Java: Introduction and Key Points
  • Java: Object Pool Design Pattern

Trending

  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • The 4 R’s of Pipeline Reliability: Designing Data Systems That Last
  • Java Virtual Threads and Scaling
  • Cookies Revisited: A Networking Solution for Third-Party Cookies
  1. DZone
  2. Coding
  3. Languages
  4. Using Flyweight Design Pattern In Java

Using Flyweight Design Pattern In Java

In this article, explore the Flyweight design pattern in Java.

By 
Brijesh Saxena user avatar
Brijesh Saxena
DZone Core CORE ·
Oct. 22, 20 · Tutorial
Likes (6)
Comment
Save
Tweet
Share
8.0K Views

Join the DZone community and get the full member experience.

Join For Free

I am here to discuss another structural design pattern named Flyweight Design Pattern. 

Flyweight Design Pattern

  • The Flyweight Design Pattern is a Structural Design Pattern and one of the Gang of Four design patterns. 
  • The Flyweight pattern is used to minimize the memory usage by sharing as much data as possible with other similar objects.
  • The Flyweight pattern provides a way to reduce the number of objects created and to decrease memory footprint and increase performance.
  • The Flyweight pattern tries to reuse already existing similar kind objects by storing them in a collection which act like a cache and creates new object when no matching object is found.
  • The Flyweight objects we create as immutable. This means that they cannot be modified once they have been constructed. Making flyweight objects as immutable helps while sharing them with other objects. 
  • The data structures for graphical representation of characters in a Word Processor is a very good classical example of Flyweight pattern.
  • The String Interning is another very good example of Flyweight pattern.
  • The Flyweight pattern helps us avoiding having large number of objects and allow us to effectively used the created objects by reusing them as much as possible.
  • The Flyweight object essentially has two different kind of attributes – 
    • Intrinsic - An intrinsic (invariant) state attribute is stored and shared in the flyweight object. It is independent of flyweight’s context. So, as the best practice we should make intrinsic states immutable.
    • Extrinsic - An extrinsic (variant) state attribute does not store and share in the flyweight object because it depends on flyweight’s context and varies as context change. Generally, we store and maintain the extrinsic state in the Client objects. We need to pass this extrinsic state to the flyweight object for object creation and processing.

Coffee Shop Example Without Using Flyweight Design Pattern

Suppose there is a Coffee shop that serves coffee with different flavors and latte art.

Here is the code for CoffeeFlavour enum to provide supported flavors of coffee. 

Java
 




x
18


 
1
package org.trishinfotech.flyweight;
2

          
3
public enum CoffeeFlavour {
4

          
5
    CAPPUCCINO("Cappuccino"), ESPRESSO("Espresso"), FRAPPUCCINO("Frappuccino"), AFFOGATO("Affogato"), LATTE("Latte");
6

          
7
    private String name;
8

          
9
    CoffeeFlavour(String name) {
10
        this.name = name;
11
    }
12

          
13
    public String getName() {
14
        return name;
15
    }
16

          
17
}
18

          



Also here the code for CoffeeLatteArt enum to provide supported latte art of coffee. Latte art is a method of preparing coffee created by pouring microfoam into a shot of espresso and resulting in a pattern or design on the surface of the latte. It can also be created or embellished by simply "drawing" in the top layer of foam.  

Java
 




xxxxxxxxxx
1
19


 
1
package org.trishinfotech.flyweight;
2

          
3
public enum CoffeeLatteArt {
4

          
5
    DISNEY("Disney"), LITTLE_BUNNY("Little Bunny"), FRENCH("French"), BARISTA_SWAG("Barista Swag"),
6
    FISHBONE("Fishbone"), MALAYSIAN_BUDDHA("Malaysian Buddha"), CAT("Cat");
7

          
8
    private String name;
9

          
10
    CoffeeLatteArt(String name) {
11
        this.name = name;
12
    }
13

          
14
    public String getName() {
15
        return name;
16
    }
17

          
18
}
19

          



Below is the code for Coffee class. I made Coffee as immutable object.

Java
 




x


 
1
package org.trishinfotech.flyweight.without;
2

          
3
import org.trishinfotech.flyweight.CoffeeFlavour;
4
import org.trishinfotech.flyweight.CoffeeLatteArt;
5

          
6
public class Coffee {
7

          
8
    protected final CoffeeFlavour flavourName;
9
    protected final CoffeeLatteArt latteArt;
10

          
11
    protected Coffee(CoffeeFlavour flavourName, CoffeeLatteArt latteArt) {
12
        super();
13
        this.flavourName = flavourName;
14
        this.latteArt = latteArt;
15
    }
16

          
17
    public CoffeeFlavour getFlavourName() {
18
        return flavourName;
19
    }
20

          
21
    public CoffeeLatteArt getLatteArt() {
22
        return latteArt;
23
    }
24

          
25
}



Also, to make the example comparable with another example by using Flyweight pattern, I wrote a factory named CoffeeFactory which will:

  • Allow using restricted access to the Coffee constructor (protected).
  • Provide a factory method named makeCoffee to create objects of Coffee class.
  • Create and maintain a collection of total number of Coffee objects created.
Java
 




xxxxxxxxxx
1
24


 
1
package org.trishinfotech.flyweight.without;
2

          
3
import java.util.ArrayList;
4
import java.util.List;
5

          
6
import org.trishinfotech.flyweight.CoffeeFlavour;
7
import org.trishinfotech.flyweight.CoffeeLatteArt;
8

          
9
public class CoffeeFactory {
10

          
11
    protected static List<Coffee> coffeeList = new ArrayList<Coffee>();
12

          
13
    public static Coffee makeCoffee(CoffeeFlavour flavourName, CoffeeLatteArt latteArt) {
14
        Coffee coffee = new Coffee(flavourName, latteArt);
15
        System.out.printf("Making '%s' with Latte Art '%s'.\n", coffee.getFlavourName(), coffee.getLatteArt());
16
        coffeeList.add(coffee);
17
        return coffee;
18
    }
19

          
20
    public static int getNumberOfCoffee() {
21
        return coffeeList.size();
22
    }
23
}
24

          



Here's the code for Order class:

Java
 




x


 
1
package org.trishinfotech.flyweight.without;
2

          
3
import org.trishinfotech.flyweight.CoffeeFlavour;
4
import org.trishinfotech.flyweight.CoffeeLatteArt;
5

          
6
public class Order {
7

          
8
    protected Coffee coffee;
9

          
10
    public Order(Coffee coffee) {
11
        super();
12
        this.coffee = coffee;
13
    }
14

          
15
    public static Order of(CoffeeFlavour flavourName, CoffeeLatteArt latteArt, int tableNumber) {
16
        Coffee coffee = CoffeeFactory.makeCoffee(flavourName, latteArt);
17
        System.out.printf("Serving to table '%d'.\n", tableNumber);
18
        System.out.println("------------------------------------------------------");
19
        return new Order(coffee);
20
    }
21

          
22
    public Coffee getCoffee() {
23
        return coffee;
24
    }
25

          
26
}



Now the code for CoffeeShop class. CoffeeShop maintains the list of orders served.

Java
 




xxxxxxxxxx
1
20


 
1
package org.trishinfotech.flyweight.without;
2

          
3
import java.util.ArrayList;
4

          
5
import org.trishinfotech.flyweight.CoffeeFlavour;
6
import org.trishinfotech.flyweight.CoffeeLatteArt;
7

          
8
public class CoffeeShop {
9
    
10
    private static final ArrayList<Order> orders = new ArrayList<>();
11

          
12
    public void takeOrder(CoffeeFlavour flavourName, CoffeeLatteArt latteArt, int tableNumber) {
13
        orders.add(Order.of(flavourName, latteArt, tableNumber));
14
    }
15

          
16
    public static int getNumberOfOrders() {
17
        return orders.size();
18
    }
19

          
20
}



And now the Main class to execute and test the output.

Java
 




x


 
1
package org.trishinfotech.flyweight.without;
2

          
3
import org.trishinfotech.flyweight.CoffeeFlavour;
4
import org.trishinfotech.flyweight.CoffeeLatteArt;
5

          
6
public class Main {
7
    public static void main(String[] args) {
8
        CoffeeShop shop = new CoffeeShop();
9
        shop.takeOrder(CoffeeFlavour.CAPPUCCINO, CoffeeLatteArt.BARISTA_SWAG, 5);
10
        shop.takeOrder(CoffeeFlavour.AFFOGATO, CoffeeLatteArt.FRENCH, 7);
11
        shop.takeOrder(CoffeeFlavour.ESPRESSO, CoffeeLatteArt.FISHBONE, 1);
12
        shop.takeOrder(CoffeeFlavour.LATTE, CoffeeLatteArt.DISNEY, 3);
13
        shop.takeOrder(CoffeeFlavour.CAPPUCCINO, CoffeeLatteArt.CAT, 2);
14
        shop.takeOrder(CoffeeFlavour.ESPRESSO, CoffeeLatteArt.FISHBONE, 8);
15
        shop.takeOrder(CoffeeFlavour.AFFOGATO, CoffeeLatteArt.BARISTA_SWAG, 4);
16
        shop.takeOrder(CoffeeFlavour.CAPPUCCINO, CoffeeLatteArt.DISNEY, 10);
17
        shop.takeOrder(CoffeeFlavour.LATTE, CoffeeLatteArt.LITTLE_BUNNY, 6);
18
        shop.takeOrder(CoffeeFlavour.FRAPPUCCINO, CoffeeLatteArt.DISNEY, 9);
19

          
20
        System.out.println("Number of Order Objects: " + CoffeeShop.getNumberOfOrders());
21
        System.out.println("Number of Coffee Objects: " + CoffeeFactory.getNumberOfCoffee());
22
    }
23
}



And below is the output of the the program:

Java
 




xxxxxxxxxx
1
33


 
1
Making 'CAPPUCCINO' with Latte Art 'BARISTA_SWAG'.
2
Serving to table '5'.
3
------------------------------------------------------
4
Making 'AFFOGATO' with Latte Art 'FRENCH'.
5
Serving to table '7'.
6
------------------------------------------------------
7
Making 'ESPRESSO' with Latte Art 'FISHBONE'.
8
Serving to table '1'.
9
------------------------------------------------------
10
Making 'LATTE' with Latte Art 'DISNEY'.
11
Serving to table '3'.
12
------------------------------------------------------
13
Making 'CAPPUCCINO' with Latte Art 'CAT'.
14
Serving to table '2'.
15
------------------------------------------------------
16
Making 'ESPRESSO' with Latte Art 'FISHBONE'.
17
Serving to table '8'.
18
------------------------------------------------------
19
Making 'AFFOGATO' with Latte Art 'BARISTA_SWAG'.
20
Serving to table '4'.
21
------------------------------------------------------
22
Making 'CAPPUCCINO' with Latte Art 'DISNEY'.
23
Serving to table '10'.
24
------------------------------------------------------
25
Making 'LATTE' with Latte Art 'LITTLE_BUNNY'.
26
Serving to table '6'.
27
------------------------------------------------------
28
Making 'FRAPPUCCINO' with Latte Art 'DISNEY'.
29
Serving to table '9'.
30
------------------------------------------------------
31
Number of Order Objects: 10
32
Number of Coffee Objects: 10
33

          



Please notice that the number of Coffee Objects are 10.

Coffee Shop Example by Using Flyweight Design Pattern

Now the same example by using Flyweight Design Pattern. I will try to highlight the differences and also the benefits of using flyweight pattern.

Here's the code for the Coffee class:

Java
 




x


 
1
package org.trishinfotech.flyweight.with;
2

          
3
import org.trishinfotech.flyweight.CoffeeFlavour;
4
import org.trishinfotech.flyweight.CoffeeLatteArt;
5

          
6
public class Coffee {
7

          
8
    protected final CoffeeFlavour flavourName; // intrinsic attribute
9

          
10
    protected Coffee(CoffeeFlavour flavourName) {
11
        super();
12
        this.flavourName = flavourName;
13
    }
14

          
15
    public CoffeeFlavour getFlavourName() {
16
        return flavourName;
17
    }
18

          
19
    protected CoffeeLatteArt applyLatteArt(CoffeeLatteArt latteArt) {
20
        // CoffeeLatteArt latteArt will be act as extrinsic attribute
21
        // So, that will be required in creating and processing of Coffee object as
22
        // method parameters and will not be stored as class members.
23
        return latteArt;
24
    }
25

          
26
}



Hare's the code for CoffeeFactory class:

Java
 




x


 
1
package org.trishinfotech.flyweight.with;
2

          
3
import java.util.WeakHashMap;
4

          
5
import org.trishinfotech.flyweight.CoffeeFlavour;
6
import org.trishinfotech.flyweight.CoffeeLatteArt;
7

          
8
public class CoffeeFactory {
9

          
10
    protected static WeakHashMap<CoffeeFlavour, Coffee> coffeeMap = new WeakHashMap<CoffeeFlavour, Coffee>();
11
    
12
    public static Coffee makeCoffee(CoffeeFlavour flavourName, CoffeeLatteArt latteArt) {
13
        Coffee coffee = coffeeMap.get(flavourName);
14
        if (coffee == null) {
15
            coffee = new Coffee(flavourName);
16
            coffeeMap.put(flavourName, coffee);
17
        }
18
        System.out.printf("Making '%s' with Latte Art '%s'.\n", coffee.getFlavourName(),
19
                coffee.applyLatteArt(latteArt));
20
        return coffee;
21
    }
22

          
23
    public static int getNumberOfCoffee() {
24
        return coffeeMap.size();
25
    }
26
    
27
}
28

          



As you can see that the CoffeeFactory maintains a collection using CoffeeFlavour (intrinsic attribute) as key. This will help us reducing the number of objects created and reusing the existing one.

Here's the code for the Order class:

Java
 




x


 
1
package org.trishinfotech.flyweight.with;
2

          
3
import org.trishinfotech.flyweight.CoffeeFlavour;
4
import org.trishinfotech.flyweight.CoffeeLatteArt;
5

          
6
public class Order {
7

          
8
    protected Coffee coffee;
9

          
10
    public Order(Coffee coffee) {
11
        super();
12
        this.coffee = coffee;
13
    }
14

          
15
    public static Order of(CoffeeFlavour flavourName, CoffeeLatteArt latteArt, int tableNumber) {
16
        Coffee coffee = CoffeeFactory.makeCoffee(flavourName, latteArt);
17
        System.out.printf("Serving to table '%d'.\n", tableNumber);
18
        System.out.println("------------------------------------------------------");
19
        return new Order(coffee);
20
    }
21

          
22
    public Coffee getCoffee() {
23
        return coffee;
24
    }
25

          
26
}



Here's the code for CoffeeShop class:

Java
 




x


 
1
package org.trishinfotech.flyweight.with;
2

          
3
import java.util.ArrayList;
4

          
5
import org.trishinfotech.flyweight.CoffeeFlavour;
6
import org.trishinfotech.flyweight.CoffeeLatteArt;
7

          
8
public class CoffeeShop {
9
    
10
    private static final ArrayList<Order> orders = new ArrayList<>();
11

          
12
    public void takeOrder(CoffeeFlavour flavourName, CoffeeLatteArt latteArt, int tableNumber) {
13
        orders.add(Order.of(flavourName, latteArt, tableNumber));
14
    }
15

          
16
    public static int getNumberOfOrders() {
17
        return orders.size();
18
    }
19

          
20
}



Now its time to write Main class to execute and test the output:

Java
 




x


 
1
package org.trishinfotech.flyweight.with;
2

          
3
import org.trishinfotech.flyweight.CoffeeFlavour;
4
import org.trishinfotech.flyweight.CoffeeLatteArt;
5

          
6
public class Main {
7
    public static void main(String[] args) {
8
        CoffeeShop shop = new CoffeeShop();
9
        shop.takeOrder(CoffeeFlavour.CAPPUCCINO, CoffeeLatteArt.BARISTA_SWAG, 5);
10
        shop.takeOrder(CoffeeFlavour.AFFOGATO, CoffeeLatteArt.FRENCH, 7);
11
        shop.takeOrder(CoffeeFlavour.ESPRESSO, CoffeeLatteArt.FISHBONE, 1);
12
        shop.takeOrder(CoffeeFlavour.LATTE, CoffeeLatteArt.DISNEY, 3);
13
        shop.takeOrder(CoffeeFlavour.CAPPUCCINO, CoffeeLatteArt.CAT, 2);
14
        shop.takeOrder(CoffeeFlavour.ESPRESSO, CoffeeLatteArt.FISHBONE, 8);
15
        shop.takeOrder(CoffeeFlavour.AFFOGATO, CoffeeLatteArt.BARISTA_SWAG, 4);
16
        shop.takeOrder(CoffeeFlavour.CAPPUCCINO, CoffeeLatteArt.DISNEY, 10);
17
        shop.takeOrder(CoffeeFlavour.LATTE, CoffeeLatteArt.LITTLE_BUNNY, 6);
18
        shop.takeOrder(CoffeeFlavour.FRAPPUCCINO, CoffeeLatteArt.DISNEY, 9);
19

          
20
        System.out.println("------------------------------------------------------------");
21
        System.out.println("Number of Order Objects: " + CoffeeShop.getNumberOfOrders());
22
        System.out.println("Number of Coffee Objects: " + CoffeeFactory.getNumberOfCoffee());
23
    }
24
}



And below is the output of the program:

Java
 




xxxxxxxxxx
1
34


 
1
Making 'CAPPUCCINO' with Latte Art 'BARISTA_SWAG'.
2
Serving to table '5'.
3
------------------------------------------------------
4
Making 'AFFOGATO' with Latte Art 'FRENCH'.
5
Serving to table '7'.
6
------------------------------------------------------
7
Making 'ESPRESSO' with Latte Art 'FISHBONE'.
8
Serving to table '1'.
9
------------------------------------------------------
10
Making 'LATTE' with Latte Art 'DISNEY'.
11
Serving to table '3'.
12
------------------------------------------------------
13
Making 'CAPPUCCINO' with Latte Art 'CAT'.
14
Serving to table '2'.
15
------------------------------------------------------
16
Making 'ESPRESSO' with Latte Art 'FISHBONE'.
17
Serving to table '8'.
18
------------------------------------------------------
19
Making 'AFFOGATO' with Latte Art 'BARISTA_SWAG'.
20
Serving to table '4'.
21
------------------------------------------------------
22
Making 'CAPPUCCINO' with Latte Art 'DISNEY'.
23
Serving to table '10'.
24
------------------------------------------------------
25
Making 'LATTE' with Latte Art 'LITTLE_BUNNY'.
26
Serving to table '6'.
27
------------------------------------------------------
28
Making 'FRAPPUCCINO' with Latte Art 'DISNEY'.
29
Serving to table '9'.
30
------------------------------------------------------
31
------------------------------------------------------------
32
Number of Order Objects: 10
33
Number of Coffee Objects: 5
34

          



Same output, but the number of Coffee objects is only 5 by using the Flyweight pattern.

That's all! I hope this tutorial helps you understand the Flyweight Design Pattern.

Source code can be found here: Flyweight Design Pattern Sample Code 

Liked the article? Please don't forget to press that like button. Happy coding!

Need more articles, please visit my profile: Brijesh Saxena.

Java (programming language) Design Object (computer science)

Opinions expressed by DZone contributors are their own.

Related

  • Object Relational Behavioral Design Patterns in Java
  • Distribution Design Patterns in Java - Data Transfer Object (DTO) And Remote Facade Design Patterns
  • Context Object Design Pattern in Java: Introduction and Key Points
  • Java: Object Pool Design Pattern

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!