Pattern to avoid direct dependency

Hi All. I have some questions regarding to patterns to avoid direct dependency.

Assuming I have a type, let's say it call struct LibraryStruct, I am thinking to avoid to directly use this type so in the future it is easier to swap out in case I need to.

What I was thinking is to write a wrapper struct to wrap the original struct, and then defines a bunch of methods on top of the inner struct. But it seems it is a very tedious process.

use external::LibraryStruct

pub struct WrapperLibraryStruct{
inner: LibraryStruct,
}

// However, I will need to write a lot of boil plate code to copy 
// the inner method to WrapperLibraryStruct

Is there a better way to achieve this? Or should I directly depend on the LibraryStruct?


More context. The LibraryStruct is Flatbuffers Struct. I want to make it to be flexiable so it is easier to swap out is needed.


Thanks in advance!

What you talking about here is called Facade design pattern. Essentially you need to do what you are describing, but maybe not exactly the way you are describing. The way you would normally do it in a OOP language is to make it polymorphic either through inheritance or by implementing a common interface.

What is this struct you want to avoid using directly? Does it have many fields? A good SE practice here would be - instead of directly mapping all the fields, you should create an interface that will behave in the way you need, and then you wrap your dependency in that interface. If you at any point want to swap out the dependency, your interface won't change in any way (at least hopefully, if it was designed right).

What I mean is, instead of writing things like getX() and setX(x) for all fields in the struct, you make methods that will do what you want. Make an initialize method that will take in the arguments you need to use in that struct and then make other methods that will do things you need with the struct's data.

2 Likes

For achieving this, you'd need a bit of boiler plate undoubtedly. But there is another thing - maybe you don't need all the operations of the thing you're wrapping, so you probably want to wrap only the methods you actually need.
That's where you need to decide upon a common interface. A pattern that I've found useful is:

pub struct WrapperLibraryStruct<P> {
      inner: P
}

impl<P> WrapperLibraryStruct<P>
   where P: LibraryProvider {
}

The LibraryProvider trait defines the "things" you need from the external library in order to define your own wrapper. Then, you can implement LibraryProvider for each external library you need and use them interchangeably.
Btw, this is essentially the Facade pattern @sgrey mentioned, modified to fit Rust.

1 Like

Thanks for all the great answers! Really appreciate