Skip to content

Commit

Permalink
decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
lpxxn committed Feb 28, 2020
1 parent c8c72ed commit 66078ca
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@
| Pattern | Description | Status |
|:-------:|:----------- |:------:|
| [Adapter](/structural/adapter.rs) | allows objects with incompatible interfaces to collaborate. ||
| [Decorator](/structural/decorator.rs) | Adds behavior to an object, statically or dynamically ||
6 changes: 3 additions & 3 deletions structural/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,19 @@ impl Target for Adapter {
// The client code supports all classes that follow the Target trait.
struct Client;
impl Client {
fn client_code<T: Target>(target: T) {
fn client_code<T: Target>(target: &T) {
println!("{}", target.get_request());
}
}

fn main() {
println!("Client: I can work just fine with the Target objects:");
Client::clinet_code(DefaultTarget {});
Client::client_code(&DefaultTarget {});
let adaptee = Rc::new(Adaptee::new("hello world".to_string()));
println!("Client: The Adaptee class has a weird interface. See, I don't understand it:");
println!("Adaptee: {}", adaptee.specific_request());

println!("Client: But I can work with it via the Adapter:");
let adapter = Adapter::new(adaptee);
Client::clinet_code(adapter);
Client::client_code(&adapter);
}
88 changes: 88 additions & 0 deletions structural/decorator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use std::rc::Rc;

// The base Component trait defines operations that can be altered by
// decorators.
trait Component {
fn operation(&self) -> String;
}

// Concrete Components provide default implementations of the operations.
// There might be several variations of these classes.
struct ConcreteComponent {}

impl Component for ConcreteComponent {
fn operation(&self) -> String {
"ConcreteComponent".to_string()
}
}

// The base Decorator class follows the same interface as the other
// components. The primary purpose of this class is to define the wrapping
// interface for all concrete decorators. The default implementation of the
// wrapping code might include a field for storing a wrapped component and
// the means to initialize it.
trait Decorator: Component {
fn new(component: Rc<dyn Component>) -> Self;
}

// Concrete Decorators call the wrapped object and alter its result in some
// way.
struct ConcreteDecoratorA {
component: Rc<dyn Component>,
}

impl Decorator for ConcreteDecoratorA {
fn new(component: Rc<dyn Component>) -> Self {
ConcreteDecoratorA {
component,
}
}
}

impl Component for ConcreteDecoratorA {
fn operation(&self) -> String {
format!("ConcreteDecoratorA: {}", self.component.operation())
}
}

struct ConcreteDecoratorB {
component: Rc<dyn Component>,
}

impl Decorator for ConcreteDecoratorB {
fn new(component: Rc<dyn Component>) -> Self {
ConcreteDecoratorB {
component,
}
}
}

impl Component for ConcreteDecoratorB {
fn operation(&self) -> String {
format!("ConcreteDecoratorB: {}", self.component.operation())
}
}

// The client code works with all objects using the Component interface.
// This way it can stay independent of the concrete classes of
// components it works with.
struct Client;

impl Client {
fn client_code<T: Component>(component: &T) {
println!("result: {}", component.operation())
}
}

fn main() {
let component = Rc::new(ConcreteComponent {});
println!("client: i get a simple component: ");
Client::client_code(component.as_ref());
println!("client: now I've got a decorated component:");
let decorator_a1 = ConcreteDecoratorA::new(component.clone());
Client::client_code(&decorator_a1);

let decorator_a2 = ConcreteDecoratorB::new(Rc::new(decorator_a1));
Client::client_code(&decorator_a2);

}

0 comments on commit 66078ca

Please sign in to comment.