Part 5: Proxy and Flyweight Design Patterns (GoF)

We will explore the Proxy and Flyweight Design Patterns under the Structural Design Patterns.

In partnership with

Hello “👋

Welcome to another week, another opportunity to become a Great Backend Engineer.

Today’s issue is brought to you by Masteringbackend → A great resource for backend engineers. We offer next-level backend engineering training and exclusive resources.

Before we get started, I have a few announcements:

We recently launched the first modules of three of our courses with a 63% discount for you. Use the coupon code PRESALE at checkout.

Here are what to expect in each course.

  • 10+ in-depth modules

  • 50+ in-depth chapters

  • 160+ high-quality lessons

  • 60+ hours of video training content

Note that the discounted prices increase monthly as we add new modules. Also, you can pick up a single course from our collection on the MB Platform.

Check this out:

🦾 Master AI & ChatGPT for FREE in just 3 hours 🤯

1 Million+ people have attended, and are RAVING about this AI Workshop.
Don’t believe us? Attend it for free and see it for yourself.

Highly Recommended: 🚀

Join this 3-hour Power-Packed Masterclass worth $399 for absolutely free and learn 20+ AI tools to become 10x better & faster at what you do

🗓️ Tomorrow | ⏱️ 10 AM EST

In this Masterclass, you’ll learn how to:

🚀 Do quick excel analysis & make AI-powered PPTs 
🚀 Build your own personal AI assistant to save 10+ hours
🚀 Become an expert at prompting & learn 20+ AI tools
🚀 Research faster & make your life a lot simpler & more…

Now, back to the business of today.

In this series, I will explore Design Patterns, their types, the GoF design patterns, drawbacks, and benefits for backend engineers.

This comes from my new Vue.js book on “Vue Design Patterns”. However, I’m only transferring the knowledge to backend engineers in this series.

Today, we will explore the Proxy and Flyweight Design Patterns under the Structural Design Patterns.

Let’s get started quickly.

What is a Proxy Pattern

The proxy pattern provides a surrogate or placeholder for another object to control access to it. For instance, managing access to an object that is expensive to instantiate.

It allows for additional functionality when accessing an object, such as controlling access, managing resources, lazy loading, logging, or even modifying requests or responses.

The Proxy Pattern is especially helpful when working with expensive objects to create or manage, or when you need to add behavior before or after interactions with the original object.

Here’s a code snippet:

class RealService {
    performAction() {
        console.log("Action performed by the real service.");
    }
}

First, we created a service called RealService, the service that is used to perform expensive actions.

However, we need a way to enforce some security or protect sensitive resources without touching the real service. That’s where the Proxy Pattern comes in.

class AuthProxy {
    constructor(user, service) {
        this.user = user;
        this.service = service;
    }

    performAction() {
        if (this.user.hasAccess) {
            this.service.performAction();
        } else {
            console.log("Access denied: You do not have permission to perform this action.");
        }
    }
}

Next, we created an AuthProxy service which will allow us to enforce security or permission rules before allowing access to the original object. Also, we can use it to protect sensitive resources from unauthorized access without changing the underlying service.

// Client code
const user = { name: "John", hasAccess: false };
const realService = new RealService();
const proxy = new AuthProxy(user, realService);

proxy.performAction();

Above, shows how to utilize the AuthProxy and the RealService class in your code. Here, we instantiate both classes and pass in the instance of the RealService as part of the parameter to the AuthProxy class.

Loading an Image with Proxy Pattern

Here’s another example of loading an image. If you are working with a system that loads large images, you might want to delay the actual loading of the image until it’s needed (e.g., when the image is displayed on the screen).

class RealImage {
    constructor(filename) {
        this.filename = filename;
        this.loadImage();
    }

    loadImage() {
        console.log(`Loading image from file: ${this.filename}`);
    }

    display() {
        console.log(`Displaying image: ${this.filename}`);
    }
}
   

The code snippet above creates an image class with two methods to load and display images respectively.

class ImageProxy {
    constructor(filename) {
        this.filename = filename;
        this.realImage = null;
    }

    display() {
        if (!this.realImage) {
            this.realImage = new RealImage(this.filename);  // Load image only when needed
        }
        this.realImage.display();
    }
}

Next, we created a Proxy pattern to help us display an image only when it is needed and only when the real image is loaded.

// Client code
const image = new ImageProxy("large-image.png");
image.display();  // Image loaded and displayed only when display() is called

The code snippet above shows how to use the Proxy Pattern in our code above.

Here is how the Proxy Pattern is useful:

  • Access control: The Proxy Pattern can restrict or manage access to sensitive resources, making it ideal for authentication, security, and permission management.

  • Lazy loading: It can delay the creation of expensive objects until they're needed, improving performance and resource efficiency.

  • Logging and monitoring: A proxy can transparently log or monitor method calls, enabling auditing or debugging without changing the original object.

  • Remote access: It can facilitate interaction with remote services or objects, abstracting the communication details from the client.

  • Resource management: Proxies can control resource usage, such as managing connection pools or limiting access to shared resources.

  • Placeholder for expensive objects: The Proxy Pattern provides a lightweight substitute for expensive objects, delaying their creation until necessary.

Overall, the Proxy Pattern provides a flexible and efficient way to manage access to resources, optimize performance, and add additional functionality to objects without changing their underlying implementation.

What is a Flyweight Pattern

The Flyweight Pattern is useful because it helps reduce memory consumption and improve performance by sharing common parts of objects across multiple instances.

It is especially beneficial when dealing with large numbers of similar objects that share common data.

The Flyweight Pattern ensures that memory usage is optimized by avoiding the creation of duplicate data and instead reusing shared states across different instances.

Let’s look at an example:

A text editor might contain millions of characters with different fonts, styles, and sizes. By using the Flyweight Pattern, the editor can share common glyphs and styles across characters, reducing memory usage.

class FontStyle {
    constructor(font, size, color) {
        this.font = font;
        this.size = size;
        this.color = color;
    }
}

In the code snippet above, we created a FontStyle class to house all the properties related to fonts.


class FontFactory {
    constructor() {
        this.styles = {};
    }

    getFontStyle(font, size, color) {
        const key = `${font}-${size}-${color}`;
        if (!this.styles[key]) {
            this.styles[key] = new FontStyle(font, size, color);
        }
        return this.styles[key];
    }
}

Next, we created a FontFactory class that allows the text editor to scale by sharing font styles across multiple characters.


// Client code
const factory = new FontFactory();

const style1 = factory.getFontStyle('Arial', 12, 'Black');
const style2 = factory.getFontStyle('Arial', 12, 'Black');  // Reused

console.log(style1 === style2);  // true (shared object)

The last code snippet shows how to use the Flyweight Pattern in our client code.

Here is how the Flyweight Pattern is useful:

The Flyweight Pattern is highly beneficial in scenarios where you need to manage a large number of similar objects efficiently. The main benefits include:

  • Memory optimization: It reduces memory consumption by sharing common parts of objects, minimizing duplication.

  • Performance improvement: It improves performance by reducing the number of objects in memory and reusing existing instances.

  • Efficient management of large-scale systems: The pattern makes it easier to handle systems with millions of objects, such as in 3D rendering, text processing, or large datasets.

  • Clear separation of state: It allows for the separation of shared (intrinsic) and unique (extrinsic) states, making the system easier to manage and optimize.

  • Supports caching and reuse: The Flyweight Pattern promotes caching of shared objects, reducing the need to create new instances repeatedly.

Overall, the Flyweight Pattern is a powerful tool for optimizing memory usage and improving the scalability of systems that deal with large numbers of similar objects.

That will be all for today. I like to keep this newsletter short.

Today, I discussed the Proxy and Flyweight Patterns, you learned how to implement them, their similarities, and when to use which.

Next week, I will start exploring the Facade, Bridge, and Decorator Design Patterns.

Don’t miss it. Share with a friend

Did you learn any new things from this newsletter this week? Please reply to this email and let me know. Feedback like this encourages me to keep going.

See you on Next Week.

Remember to start learning backend engineering from our courses:

Top 5 Remote Backend Jobs this week

Here are the top 5 Backend Jobs you can apply to now.

👨‍💻 Stripe
✍️ Backend / API Engineer, Local Payment Methods
📍Remote, Dublin, Ireland
💰 Click on Apply for salary details
Click here to Apply for this role.

👨‍💻 LaunchDarkly
✍️ Backend Engineer - AI
📍Remote, US
💰 Click on Apply for salary details
Click here to Apply for this role.

👨‍💻 Pinterest
✍️ Backend Software Engineer
📍Remote, Worldwide
💰 Click on Apply for salary details
Click here to Apply for this role.

👨‍💻Sportradar
✍️ Backend Engineer
📍Remote
💰 Click on Apply for salary details
Click here to Apply for this role.

Want more Remote Backend Jobs? Visit GetBackendJobs.com

Backend Engineering Resources

Whenever you're ready

There are 4 ways I can help you become a great backend engineer:

1. The MB Platform: Join 1000+ backend engineers learning backend engineering on the MB platform. Build real-world backend projects, track your learnings and set schedules, learn from expert-vetted courses and roadmaps, and solve backend engineering tasks, exercises, and challenges.

2. The MB Academy:​ The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

3. MB Video-Based Courses: Join 1000+ backend engineers who learn from our meticulously crafted courses designed to empower you with the knowledge and skills you need to excel in backend development.

4. GetBackendJobs: Access 1000+ tailored backend engineering jobs, manage and track all your job applications, create a job streak, and never miss applying. Lastly, you can hire backend engineers anywhere in the world.

LAST WORD 👋 

How am I doing?

I love hearing from readers, and I'm always looking for feedback. How am I doing with The Backend Weekly? Is there anything you'd like to see more or less of? Which aspects of the newsletter do you enjoy the most?

Hit reply and say hello - I'd love to hear from you!

Stay awesome,
Solomon

I moved my newsletter from Substack to Beehiiv, and it's been an amazing journey. Start yours here.

Reply

or to participate.