Unlocking the Power of Rust: Exploring the Extension Object Pattern for Ultimate Flexibility

Photo by Kindel Media: https://www.pexels.com/photo/a-close-up-shot-of-a-usb-hub-attached-on-a-laptop-7054723/

Introduction

The extension object pattern is like adding extra features to something without changing what it is. It’s a bit like putting a gift inside another gift. In this case, Rust doesn’t directly support this pattern like some other languages do, but we’ll see how to make it work in Rust.

Implementation in Rust

We start by creating a trait called BasicWindow. This trait defines two methods: open() and close(). These methods don’t do much, just open and close something.

trait BasicWindow {
    fn open(&self);
    fn close(&self);
}

Next we come to our basic window, the Window struct. It has a title:

#[derive(Clone)]
struct Window {
    title: String,
}

impl Window {
    fn new(title: String)->Self {
        Window {
            title: title.clone()
        }
    }
}

impl BasicWindow for Window {
    fn open(&self) {
        println!("Opening window with title {}",self.title);
    }
    fn close(&self) {
        println!("Closing window with title {}",self.title);
    }
}

Some things to note:

  1. Our window has a title in this example
  2. We define a method called new() to create a window
  3. The open() and close() methods simply print messages

Now, let’s step it up by creating an ExtendedWindow, which can do everything a Window can do, and more – it can rotate itself.

struct ExtendedWindow {
    window: Window,
}

impl ExtendedWindow {
    fn new(window: Window)->Self {
        ExtendedWindow {
            window: window.clone()
        }
    }

    fn rotate(&self,degrees: i16) {
        println!("Rotating window with title {} by {} degrees",self.window.title,degrees)
    }
}

impl BasicWindow for ExtendedWindow {
    fn open(&self) {
        self.window.open()
    }

    fn close(&self) {
        self.window.close()
    }
}

A few points to clarify:

  1. The new() method is used to create an ExtendedWindow.
  2. We’ve added a rotate() method for rotating the window.
  3. In the BasicWindow trait implementation, we delegate the open() and close() calls to the embedded window.

Time to test

We can now test our window setup:

fn main() {
    let window=Window::new("My window".to_string());
    let extended_window=ExtendedWindow::new(window);
    extended_window.open();
    extended_window.rotate(45);
    extended_window.close();
}

This does the following:

  1. Create a Window struct , and pass that to an ExtendedWindow struct
  2. Then we test our open(), close(), and rotate() functionalities

Conclusion

The extension object pattern is relatively easy to implement, even in existing code. It may not completely replace subclassing, but it can handle some of the same things. It also makes it simple to add functionality to objects without changing their source code, and it can help prevent having too many subclasses. This approach follows the idea of composition over inheritance, which is considered a good practice.

Leave a Reply

Your email address will not be published. Required fields are marked *