|
|
|
|
|
by josephg
402 days ago
|
|
Here's my take on implementing this in rust. I made a trait for fetching metadata, that can be implemented by Image, Video, Document, etc: trait MetadataSource {
fn fetch_metadata(&self) -> Metadata;
}
impl MetadataSource for Image { ... }
impl MetadataSource for Video { ... }
impl MetadataSource for Document { ... }
And a separate object which stores an image / video / document alongside its cached metadata: struct ThingWithMetadata<T> {
obj: T, // Assuming you need to store this too?
metadata: Option<Metadata>
}
impl<T: MetadataSource> ThingWithMetadata {
fn get_metadata(&self) -> &Metadata {
if self.metadata.is_none() {
self.metadata = Some(self.obj.fetch_metadata());
}
self.metadata.as_ref().unwrap()
}
}
Its not the most beautiful thing in the world, but it works. And it'd be easy enough to add more methods, behaviour and state to those metadata sources if you want. (Eg if you want Image to actually load / store an image or something.)In this case, it might be even simpler if you made Image / Video / Document into an enum. Then fetch_metadata could be a regular function with a match expression (switch statement). If you want to be tricky, you could even make struct ThingWithMetadata also implement MetadataSource. If you do that, you can mix and match cached and uncached metadata sources without the consumer needing to know the difference. https://play.rust-lang.org/?version=stable&mode=debug&editio... |
|
(For one thing, it's quite obvious to see that the pattern itself is rather anti-modular, and the ways generic typestate is used are also quite divergent from the usual style of inheritance-heavy OO design.)