So, I have this issue of how to correctly structure some of the types in my code and I was hoping for a suggestion. A brief description of the problem goes like this:
- I have multiple objects which have a lot (if not all) fields which are common
- Each object, however, needs to have the behaviour of a different method
- When executing various methods any modifications to the common fields are exactly the same across all objects.
So the first two suggest that I should use a trait. However, because of 3, in order not to replicate code, I made a common class, which has as fields the base and a Box. However, I’m not too confident this is a good choice and if there is a better one. Below I provide a short snippet of a simplified version of what I have so far (a playground link - https://play.rust-lang.org/?gist=b5694e5bcbc110434a6e175a7643808e)
use std::fmt::Debug;
#[derive(Default, Debug, Clone)]
pub struct Base {
field1: u32,
field2: f64,
//.... more
}
pub trait Api: Debug {
fn clone_box(&self) -> Box<Api>;
fn method1(&self, base: &Base) -> f64;
}
#[derive(Debug)]
pub struct Object {
base: Base,
api: Box<Api>
}
impl Clone for Object {
fn clone(&self) -> Self {
Object {
base: self.base.clone(),
api: self.api.clone_box()
}
}
}
impl Object {
pub fn method(&mut self) -> f64{
self.base.field1 += 1;
self.api.method1(&self.base)
}
}
#[derive(Default, Debug, Clone)]
struct Implementator1 {}
impl Api for Implementator1 {
fn clone_box(&self) -> Box<Api> {
Box::new(self.clone())
}
fn method1(&self, base: &Base) -> f64 {
base.field2 + 1.0
}
}
#[derive(Default, Debug, Clone)]
struct Implementator2 {}
impl Api for Implementator2 {
fn clone_box(&self) -> Box<Api> {
Box::new(self.clone())
}
fn method1(&self, base: &Base) -> f64 {
base.field2 + 2.0
}
}
pub fn main() {
let o1 = Object{base: Base::default(), api:Box::new(Implementator1{})};
let o2 = Object{base: Base::default(), api:Box::new(Implementator2{})};
let mut v = vec![o1, o2];
println!("{:?}", v);
println!("{}", v.get_mut(0).unwrap().method());
println!("{}", v.get_mut(1).unwrap().method());
}