# Composite

### Key points

* The key point is to have a trait to represent both, simple and composed structs.
    
* Clients should ignore the difference between compositions and individual objects.
    
* Avoid case statements to specify individual treatment to every struct, making it easier to put new types of components
    

## Participants

### Component

An abstract representation of the component

### Leaf

The simplest component, which has no children

### Composite

The sort of Component which has children

### Client

The software part that uses the composite api

## Study

In the example I am going to model glasses because I already used them in my professional career and did not have any knowledge of the composite pattern at that time, the final solution was very close to the pattern but I would suffer much less if I knew it.

### OO approach

Firstly I will show a possible approach to use as a more OO driven language, such as Java, Kotlin etc

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1680793924559/b5469081-f9dd-4f3b-837e-0fe2bb5a5fb7.png align="center")

### Implemented approach

Secondly, I will show the approach that I choose using rust, because of its differences from the language cited earlier

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1680793948464/c3b2a13f-ef6a-482e-9a83-4805d5a35c59.png align="center")

#### Code solution

```rust
pub trait Item {
    fn price(&self) -> f64;
    fn add_item(&mut self, _: Box<dyn Item>) -> Result<(), &str>{
        return Err("not implemented on a simple item")
    }
    fn remove_item(&mut self, _: usize) -> Result<(), &str>{
        return Err("not implemented on a simple item")
    }
}
```

I decided to use a default implementation to deal with component children since it would simplify the use for the Composite client. It's important to evaluate the tradeoffs here.

```rust
struct ItemComposite {
    items: Vec<Box<dyn Item>>
}

impl ItemComposite {
    fn new() -> Self {
        return ItemComposite{
            items: Vec::new()
        }
    }
}

impl Item for ItemComposite {
    fn price(&self) -> f64 {
        let prices = self.items.iter().map(|x| x.price());
        return prices.sum()
    }

    fn add_item(&mut self, i: Box<dyn Item>) -> Result<(), &str>{
        self.items.push(i);
        return Ok(())
    }

    fn remove_item(&mut self, position: usize) -> Result<(), &str>{
        _ = self.items.remove(position);
        return Ok(())
    }
}
```

Since there's no inheritance in rust, I had to state the behavior in terms of traits, just exposing the behavior and not attributes like items for example. Therefore I decided to aggregate the composed structs with an ItemComposite in contrast to inheriting it as I would do in a OO language. When composed-related operations such as price are invoked by the client the composed class does part of the operation and delegates the children-related part to the Item composite.

```rust
pub struct Lens {
    composite: ItemComposite,
    pub(crate) price: f64,
}

impl Lens {
    pub fn new(price: f64) -> Self {
        return Lens{
            composite : ItemComposite::new(),
            price,
        }
    }
}


impl Item for Lens {
    fn price(&self) -> f64 {
        return &self.price + &self.composite.price()
    }

    fn add_item(&mut self, i: Box<dyn Item>) -> Result<(), &str>{
        return self.composite.add_item(i);
    }

    fn remove_item(&mut self, i: usize) -> Result<(), &str>{
        return self.composite.remove_item(i);
    }
}

pub struct Frame {
    composite: ItemComposite,
    price: f64,
}

impl Item for Frame {
    fn price(&self) -> f64 {
        return &self.price + &self.composite.price()
    }

    fn add_item(&mut self, i: Box<dyn Item>) -> Result<(), &str>{
        return self.composite.add_item(i);
    }

    fn remove_item(&mut self, i: usize) -> Result<(), &str>{
        return self.composite.remove_item(i)
    }
}

impl Frame {
    pub fn new(price: f64) -> Self {
        return Frame{
            composite : ItemComposite::new(),
            price,
        }
    }
}

pub struct Treatment {
    pub price: f64,
}

impl Item for Treatment {
    fn price(&self) -> f64 {
        return self.price
    }
}

impl Treatment {
    pub fn new(price: f64) -> Self {
        return Treatment{
            price,
        }
    }
}

pub struct Signature {
    pub price: f64,
}

impl Signature {
    pub fn new(price: f64) -> Self {
        return Signature{
            price,
        }
    }
}

impl Item for Signature {
    fn price(&self) -> f64 {
        return self.price
    }
}
```

#### Code tests

```rust
#[cfg(test)]
mod test {
    use crate::items::*;

    #[test]
    fn calling_add_item_from_an_not_composed_item() {
        let mut treatment = Treatment::new(200.0);
        let sig = Signature::new(100.0);

        let res = treatment.add_item(Box::new(sig));

        assert!(res.is_err())
    }

    #[test]
    fn assemblying_an_complte_glass_product() {
        let treatment = Treatment::new(200.0);
        let mut lens = Lens::new(300.0);
        let _ = lens.add_item(Box::new(treatment));

        let sig = Signature::new(100.0);
        let mut frame = Frame::new(500.0);
        let _ = frame.add_item(Box::new(lens));
        let _ = frame.add_item(Box::new(sig));

        assert_eq!(frame.price(), 1100.0);
    }
}
```

## code link on my github:

[https://github.com/igorcavalcante/design\_patterns/blob/main/composite](https://github.com/igorcavalcante/design_patterns/blob/main/composite)

### Alternative rust approach

A third approach would be to create a trait that extends the item trait and adds children-related behavior. It would work but could add complexity to the API client since probably they would need to differentiate between a Leaf and a Composed struct.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1680794039737/6a6b86ed-0d90-4d92-985b-68d8e784dcf8.png align="center")

## Difficulties that I found:

Basically, all my problems were hot to adapt an OO pattern to rust. Such as

* No abstract classes with attributes
    
* Some trouble with borrowing and other kinds of compile checks
    
* Some optional aspect is to share behavior to manage the children's objects
    

## Final thoughts

It would be easier to use a more Object Oriented language to do the same job, but It could be done using Rust with good effectiveness too. As a rust learner, I had some trouble trying to figure out how to borrow variables, use traits, and use modules as anyone should have. Certainly, I will use this pattern in a case of hierarchy-organized structures

## Sources

### Design patterns

Elements of Reusable Object-Oriented Software Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides

### Composite in Rust

[https://refactoring.guru/design-patterns/composite/rust/example](https://refactoring.guru/design-patterns/composite/rust/example)

### The "Composite Pattern" in Rust

AXEL FORTUN [https://grapeprogrammer.com/composite-pattern-rust/](https://grapeprogrammer.com/composite-pattern-rust/)
