577 lines
20 KiB
Markdown
577 lines
20 KiB
Markdown
## Decorator
|
|
|
|
The last design pattern that I mention today is a `decorator`. Before we talk about it, let's extend `Cargo` class and handle a few new functionalities:
|
|
|
|
* The item may be damaged during a time (we have salty air) so it can lose his value during travelling
|
|
* The fruit may rotten, so we also want to lower its price every day
|
|
* The alcohol price should be based on it's power
|
|
* The value of item should be higher based on its type (common is cheapest but legendary has a big value)
|
|
|
|
___
|
|
|
|
## New implementation
|
|
|
|
Let's start with a new implementation of class `Fruit`. Now we inherit from `TimeObserver` to count days. We also take in account that the price will be lowered every day.
|
|
|
|
```C++
|
|
struct Fruit : public Cargo, public TimeObserver {
|
|
static constexpr int MAX_TIME = 20;
|
|
static constexpr int BASE_PRICE = 10;
|
|
int rottenCounter;
|
|
Time* time;
|
|
|
|
Fruit(Time* time, size_t amount, int rottenCounter)
|
|
: Cargo(amount), time(time), rottenCounter(rottenCounter) {
|
|
time->attach(this);
|
|
}
|
|
|
|
// Rule of 5
|
|
~Fruit() {
|
|
time->detach(this);
|
|
}
|
|
|
|
size_t getPrice() const override {
|
|
return (rottenCounter * BASE_PRICE) / MAX_TIME;
|
|
}
|
|
|
|
const std::string& name() const override {
|
|
static const std::string name = "Banana";
|
|
return name;
|
|
}
|
|
|
|
void nextDay() override {
|
|
rottenCounter = std::max(0, rottenCounter - 1);
|
|
}
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.65em" -->
|
|
|
|
___
|
|
|
|
```C++
|
|
struct Item : public Cargo, public TimeObserver {
|
|
enum class Type { Common = 100,
|
|
Rare = 300,
|
|
Epic = 1000,
|
|
Legendary = 2500 };
|
|
static constexpr int MAX_DURABILITY = 100;
|
|
Time* time;
|
|
Type type;
|
|
int durability{MAX_DURABILITY};
|
|
|
|
Item(Time* time, size_t amount, Type type)
|
|
: Cargo(amount), time(time), type(type) {
|
|
time->attach(this);
|
|
}
|
|
|
|
// Rule of 5
|
|
~Item() {
|
|
time->detach(this);
|
|
}
|
|
|
|
size_t getPrice() const override {
|
|
return (durability * static_cast<int>(type)) / MAX_DURABILITY;
|
|
}
|
|
|
|
const std::string& name() const override {
|
|
static const std::string name = "Item";
|
|
return name;
|
|
}
|
|
|
|
void nextDay() override {
|
|
durability = std::max(0, durability - 1);
|
|
}
|
|
};
|
|
```
|
|
<!-- .slide: style="font-size: 0.57em" -->
|
|
___
|
|
|
|
## Duplication of code
|
|
|
|
At the end, we also implement a `Alcohol` class. As you can see, we duplicate behavior few times. `Item` and `Fruit` may lose value each day. Price of `Item` and `Alcohol` depend on it's type etc…
|
|
|
|
```C++
|
|
struct Alcohol : public Cargo {
|
|
enum class Type { White = 100,
|
|
Spiced = 200,
|
|
Dark = 300,
|
|
Seasoned = 500 };
|
|
static constexpr int MAX_POWER = 96;
|
|
int power;
|
|
Type type;
|
|
|
|
Alcohol(size_t amount, int power, Type type)
|
|
: Cargo(amount), power(power), type(type) {}
|
|
|
|
size_t getPrice() const override {
|
|
return (power * static_cast<int>(type)) / MAX_POWER;
|
|
}
|
|
|
|
const std::string& name() const override {
|
|
static const std::string name = "Rum";
|
|
return name;
|
|
}
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.76em" -->
|
|
___
|
|
|
|
The following code works as we want to. However, whenever we want to change a logic, for instance instead of decrement the counter every day, we want to subtract `durability` and `rottenCounter` every second day. We need to do this in two places. And when we will add more cargo, we will need to do this everywhere. This is not a good example of easy to maintenance code.
|
|
|
|
```C++
|
|
int main() {
|
|
Time time;
|
|
std::unique_ptr<Cargo> cargo = std::make_unique<Item>(&time, 10, Item::Type::Epic);
|
|
|
|
for (int i = 1; i <= 15; ++i) {
|
|
std::cout << "DAY: " << i << " | Name: " << cargo->name() << " | Price: " << cargo->getPrice() << '\n';
|
|
++time;
|
|
}
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```
|
|
DAY: 1 | Name: Item | Price: 1000
|
|
DAY: 2 | Name: Item | Price: 990
|
|
DAY: 3 | Name: Item | Price: 980
|
|
DAY: 4 | Name: Item | Price: 970
|
|
DAY: 5 | Name: Item | Price: 960
|
|
DAY: 6 | Name: Item | Price: 950
|
|
DAY: 7 | Name: Item | Price: 940
|
|
DAY: 8 | Name: Item | Price: 930
|
|
DAY: 9 | Name: Item | Price: 920
|
|
DAY: 10 | Name: Item | Price: 910
|
|
DAY: 11 | Name: Item | Price: 900
|
|
DAY: 12 | Name: Item | Price: 890
|
|
DAY: 13 | Name: Item | Price: 880
|
|
DAY: 14 | Name: Item | Price: 870
|
|
DAY: 15 | Name: Item | Price: 860
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.69em" -->
|
|
___
|
|
|
|
## Drawback
|
|
|
|
According to one of SOLID rule **O**pen-close, we should write an easy to extend code, which don't require from us modification of already implemented code. Unfortunately, we need to modify each class to append a new logic, like: `decrement durability each day` or `get price based on durability or type`. What's more, we don't want to simulate `rotten of fruit` or lose `durability` by items that are stored in `shops`. So we need to add some `bool` flag like `isInShop` to ignore time elapsing. When the code grows and grows, we need to add more such flags and duplicate more code. This is definitely not the way we should develop a code. A better solution is to make a `Fruit` or `Item` class unaware of time elapsing. We can also make class `item` and `Alcohol` unaware of different types, and it's prices. This will allow to decouple the code, and make it easier to extend.
|
|
|
|
___
|
|
|
|
## Decorator
|
|
|
|
Instead of implement the whole logic to every class, and then make some `bool` flags to omit a few of them. We can use a `decorator` pattern. Let's start from the interface. The `DecoratedCargo` inherit form `Cargo` class and take as an argument `unique_ptr` for class `Cargo`. This interface has also two protected function allowing to get underlying cargo.
|
|
|
|
```C++
|
|
class DecoratedCargo : public Cargo {
|
|
public:
|
|
explicit DecoratedCargo(std::unique_ptr<Cargo>&& cargo)
|
|
: _cargo(std::move(cargo)) {
|
|
assert(_cargo);
|
|
}
|
|
|
|
protected:
|
|
Cargo& cargo() { return *_cargo; }
|
|
const Cargo& cargo() const { return *_cargo; }
|
|
|
|
private:
|
|
std::unique_ptr<Cargo> _cargo;
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.93em" -->
|
|
___
|
|
|
|
## Vulnerable
|
|
|
|
A `Vulnerable` class inherit from `TimeObserver` to simulate time elapsing and from `DecoratedCargo`. When we calculate the price, it will calculate percentage value based on `durability` and `maxDurability`. Price can be manipulated by other decorator, so we call `getPrice`.
|
|
|
|
```C++
|
|
class Vulnerable : public DecoratedCargo, public TimeObserver {
|
|
public:
|
|
Vulnerable(std::unique_ptr<Cargo>&& cargo, Time* time, int durability, int maxDurability)
|
|
: DecoratedCargo(std::move(cargo)), _time(time), _durability(durability), _maxDurability(maxDurability) {
|
|
assert(_time);
|
|
time->attach(this);
|
|
}
|
|
|
|
// Rule of 5
|
|
~Vulnerable() {
|
|
_time->detach(this);
|
|
}
|
|
|
|
void nextDay() override {
|
|
_durability = std::max(0, _durability - 1);
|
|
}
|
|
|
|
size_t getPrice() const override {
|
|
return (_durability * cargo().getPrice()) / _maxDurability;
|
|
}
|
|
|
|
const std::string& name() const override {
|
|
return cargo().name();
|
|
}
|
|
|
|
private:
|
|
Time* _time;
|
|
int _durability;
|
|
int _maxDurability;
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.64em" -->
|
|
___
|
|
|
|
## Valuable
|
|
|
|
A `Valuable` class is a template class that take `enum` as a template argument. It will be used later when we calculate a price. We will treat it as a multiplier for already calculated price.
|
|
|
|
```C++
|
|
template <typename ValueType>
|
|
class Valuable : public DecoratedCargo {
|
|
public:
|
|
Valuable(std::unique_ptr<Cargo>&& cargo, ValueType value)
|
|
: DecoratedCargo(std::move(cargo)), _value(value) {
|
|
}
|
|
|
|
size_t getPrice() const override {
|
|
return cargo().getPrice() * static_cast<int>(_value);
|
|
}
|
|
|
|
const std::string& name() const override {
|
|
return cargo().name();
|
|
}
|
|
|
|
private:
|
|
ValueType _value;
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.82em" -->
|
|
___
|
|
|
|
## Type
|
|
|
|
Because we want to make `Item` and `Alcohol` and any other type unaware about its type. We move it to the separate files. This allows us to develop new functionality without modification of existing code. For instance, when we decided later that we want to add also a `type` for `Fruit` we will create a new file and that's all! We don't need to recompile anything, and also don't need to modify anything. So even if `Fruit` is in a separate repository, and we can't modify it. We still can add new behavior.
|
|
|
|
```C++
|
|
enum class ItemType { Common = 1,
|
|
Rare = 3,
|
|
Epic = 10,
|
|
Legendary = 25 };
|
|
|
|
enum class AlcoholType { White = 1,
|
|
Spiced = 2,
|
|
Dark = 3,
|
|
Seasoned = 5 };
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.82em" -->
|
|
|
|
___
|
|
|
|
## Usage
|
|
|
|
Now we can concatenate any decorator with a `Cargo` type, so we can add new functionality `in fly`.
|
|
|
|
```C++
|
|
int main() {
|
|
Time time;
|
|
std::unique_ptr<Cargo> cargo = std::make_unique<Vulnerable>(
|
|
std::make_unique<Valuable<ItemType>>(
|
|
std::make_unique<Item>(10), ItemType::Epic),
|
|
&time, 100, 100);
|
|
|
|
for (int i = 1; i <= 15; ++i) {
|
|
std::cout << "DAY: " << i << " | Name: " << cargo->name() << " | Price: " << cargo->getPrice() << '\n';
|
|
++time;
|
|
}
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```bash
|
|
DAY: 1 | Name: Item | Price: 1000
|
|
DAY: 2 | Name: Item | Price: 990
|
|
DAY: 3 | Name: Item | Price: 980
|
|
DAY: 4 | Name: Item | Price: 970
|
|
DAY: 5 | Name: Item | Price: 960
|
|
DAY: 6 | Name: Item | Price: 950
|
|
DAY: 7 | Name: Item | Price: 940
|
|
DAY: 8 | Name: Item | Price: 930
|
|
DAY: 9 | Name: Item | Price: 920
|
|
DAY: 10 | Name: Item | Price: 910
|
|
DAY: 11 | Name: Item | Price: 900
|
|
DAY: 12 | Name: Item | Price: 890
|
|
DAY: 13 | Name: Item | Price: 880
|
|
DAY: 14 | Name: Item | Price: 870
|
|
DAY: 15 | Name: Item | Price: 860
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.67em" -->
|
|
___
|
|
|
|
## Store
|
|
|
|
If cargo is inside the store, we just don't add a `Vulnerable` decorator!
|
|
|
|
```C++
|
|
Time time;
|
|
std::unique_ptr<Cargo> cargo = std::make_unique<Vulnerable>(
|
|
std::make_unique<Valuable<ItemType>>(
|
|
std::make_unique<Item>(10), ItemType::Epic),
|
|
&time, 100, 100);
|
|
std::unique_ptr<Cargo> cargo2 =
|
|
std::make_unique<Valuable<ItemType>>(
|
|
std::make_unique<Item>(10), ItemType::Epic);
|
|
|
|
for (int i = 1; i <= 15; ++i) {
|
|
std::cout << "DAY: " << i << " | Name: " << cargo->name() << " | Price: " << cargo->getPrice();
|
|
std::cout << " |-| Name: " << cargo2->name() << " | Price: " << cargo2->getPrice() << '\n';
|
|
++time;
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```bash
|
|
DAY: 1 | Name: Item | Price: 1000 |-| Name: Item | Price: 1000
|
|
DAY: 2 | Name: Item | Price: 990 |-| Name: Item | Price: 1000
|
|
DAY: 3 | Name: Item | Price: 980 |-| Name: Item | Price: 1000
|
|
DAY: 4 | Name: Item | Price: 970 |-| Name: Item | Price: 1000
|
|
DAY: 5 | Name: Item | Price: 960 |-| Name: Item | Price: 1000
|
|
DAY: 6 | Name: Item | Price: 950 |-| Name: Item | Price: 1000
|
|
DAY: 7 | Name: Item | Price: 940 |-| Name: Item | Price: 1000
|
|
DAY: 8 | Name: Item | Price: 930 |-| Name: Item | Price: 1000
|
|
DAY: 9 | Name: Item | Price: 920 |-| Name: Item | Price: 1000
|
|
DAY: 10 | Name: Item | Price: 910 |-| Name: Item | Price: 1000
|
|
DAY: 11 | Name: Item | Price: 900 |-| Name: Item | Price: 1000
|
|
DAY: 12 | Name: Item | Price: 890 |-| Name: Item | Price: 1000
|
|
DAY: 13 | Name: Item | Price: 880 |-| Name: Item | Price: 1000
|
|
DAY: 14 | Name: Item | Price: 870 |-| Name: Item | Price: 1000
|
|
DAY: 15 | Name: Item | Price: 860 |-| Name: Item | Price: 1000
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.63em" -->
|
|
___
|
|
|
|
## Decorator
|
|
|
|
The decorator pattern can be used to extend (decorate) the functionality of a certain object statically, or in some cases at run-time, independently of other instances of the same class, provided some groundwork is done at design time. This is achieved by designing a new Decorator class that wraps the original class.
|
|
|
|
<img data-src="images/decorator_uml.png" alt="Decorator UML">
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.82em" -->
|
|
___
|
|
|
|
Decorator also helps with **D**ependency inversion. Because `decorator` classes are in low-lvl, so we can easily add a new decorator without changing anything in higher layers.
|
|
|
|
<img data-src="images/decorator_cargo__uml.png" alt="Decorator Cargo UML" height="600px">
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.76em" -->
|
|
___
|
|
|
|
## Drawbacks
|
|
|
|
Decorator is powerfull desing pattenr, but as everything it also has some drawbacks.
|
|
|
|
* <!-- .element: class="fragment fade-in" --> The main problem is that we need to use plenty of `unique_ptr` this will use more memory and also will be slower, because we need to call a few virtual functions.
|
|
* <!-- .element: class="fragment fade-in" --> If we add to many decorators, the code became hard to read
|
|
* <!-- .element: class="fragment fade-in" --> Debugging code containing decorators also may be more difficult, because we need to jump between a few of the same methods (but located in different decorators) before we reach the final result. So find a bug will be harder
|
|
* <!-- .element: class="fragment fade-in" --> If the result of one decorator has an impact on another, we may cause a hard to spot bug when we swap the order. So we shouldn't create a decorator, which should be stored in order, because a risk of concatenated them wrong is high.
|
|
___
|
|
|
|
## Different approach
|
|
|
|
As one popular proverb says: "Time is money". And if our code must be as fast as possible, and we can't afford a price, that few decorators means calling of few virtual functions, which also make the code much harder to optimize by compiler. We need to rising with decorator. I have good news for you: No, you don't need to! We have two types of polymorphism, so instead of using a `dynamic` one, let's use a `static`.
|
|
|
|
___
|
|
|
|
## Get rid of virtual
|
|
|
|
First, the class `Cargo` is no longer virtual. We don't need to implement rule of 5 and create a virtual destructor. We move constructors to `protected` section, to make it create only by derived classes (sth similar to abstract class, which we can't create).
|
|
|
|
```C++
|
|
struct Cargo {
|
|
size_t amount;
|
|
|
|
auto operator<=>(const Cargo&) const = default;
|
|
|
|
protected:
|
|
// Only derived class can create it
|
|
Cargo(size_t amount)
|
|
: amount(amount) {}
|
|
Cargo() = default;
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.96em" -->
|
|
___
|
|
|
|
Next, we also remove all virtual functions from derived classes.
|
|
|
|
```C++
|
|
struct Fruit : public Cargo {
|
|
static constexpr int BASE_PRICE = 10;
|
|
|
|
Fruit(size_t amount)
|
|
: Cargo(amount) {}
|
|
|
|
size_t getPrice() const {
|
|
return BASE_PRICE;
|
|
}
|
|
|
|
const std::string& name() const {
|
|
static const std::string name = "Banana";
|
|
return name;
|
|
}
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```C++
|
|
struct Item : public Cargo {
|
|
static constexpr int BASE_PRICE = 100;
|
|
|
|
Item(size_t amount)
|
|
: Cargo(amount) {}
|
|
|
|
size_t getPrice() const {
|
|
return BASE_PRICE;
|
|
}
|
|
|
|
const std::string& name() const {
|
|
static const std::string name = "Item";
|
|
return name;
|
|
}
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.66em" -->
|
|
___
|
|
|
|
We don't need to have a base class for decorator. We can move directly to implementation.
|
|
|
|
```C++
|
|
template <typename Neasted>
|
|
class Vulnerable : public TimeObserver {
|
|
public:
|
|
Vulnerable(Neasted neasted, Time* time, int durability, int maxDurability)
|
|
: _neasted(neasted), _time(time), _durability(durability), _maxDurability(maxDurability) {
|
|
assert(_time);
|
|
time->attach(this);
|
|
}
|
|
|
|
// Rule of 5
|
|
~Vulnerable() { _time->detach(this);}
|
|
|
|
void nextDay() override {
|
|
_durability = std::max(0, _durability - 1);
|
|
}
|
|
|
|
size_t getPrice() const {
|
|
return (_durability * _neasted.getPrice()) / _maxDurability;
|
|
}
|
|
|
|
const std::string& name() const {
|
|
return _neasted.name();
|
|
}
|
|
|
|
private:
|
|
Neasted _neasted;
|
|
Time* _time;
|
|
int _durability;
|
|
int _maxDurability;
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.62em" -->
|
|
|
|
___
|
|
|
|
As you can see, we have even less code, and we avoid a lot of virtual functions. If we decide that an object is too heavy to copy, we can pass a pointer. The main bottleneck of decorator which slows down the code was calling a lot of virtual functions. Without virtual functions, our code is much faster.
|
|
|
|
```C++
|
|
template <typename Neasted, typename ValueType>
|
|
class Valuable {
|
|
public:
|
|
Valuable(Neasted neasted, ValueType value)
|
|
: _neasted(neasted), _value(value) {
|
|
}
|
|
|
|
size_t getPrice() const {
|
|
return _neasted.getPrice() * static_cast<int>(_value);
|
|
}
|
|
|
|
const std::string& name() const {
|
|
return _neasted.name();
|
|
}
|
|
|
|
private:
|
|
Neasted _neasted;
|
|
ValueType _value;
|
|
};
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.72em" -->
|
|
___
|
|
|
|
Even usage seems more intuitive, because we don't need to create a lot of `unique_ptr` even for small objects.
|
|
|
|
```C++
|
|
int main() {
|
|
Time time;
|
|
auto cargo = Vulnerable(Valuable(Item(10), ItemType::Epic), &time, 100, 100);
|
|
auto cargo2 = Valuable(Item(10), ItemType::Epic);
|
|
|
|
for (int i = 1; i <= 15; ++i) {
|
|
std::cout << "DAY: " << i << " | Name: " << cargo.name() << " | Price: " << cargo.getPrice();
|
|
std::cout << " |-| Name: " << cargo2.name() << " | Price: " << cargo2.getPrice() << '\n';
|
|
++time;
|
|
}
|
|
}
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
|
|
```bash
|
|
DAY: 1 | Name: Item | Price: 1000 |-| Name: Item | Price: 1000
|
|
DAY: 2 | Name: Item | Price: 990 |-| Name: Item | Price: 1000
|
|
DAY: 3 | Name: Item | Price: 980 |-| Name: Item | Price: 1000
|
|
DAY: 4 | Name: Item | Price: 970 |-| Name: Item | Price: 1000
|
|
DAY: 5 | Name: Item | Price: 960 |-| Name: Item | Price: 1000
|
|
DAY: 6 | Name: Item | Price: 950 |-| Name: Item | Price: 1000
|
|
DAY: 7 | Name: Item | Price: 940 |-| Name: Item | Price: 1000
|
|
DAY: 8 | Name: Item | Price: 930 |-| Name: Item | Price: 1000
|
|
DAY: 9 | Name: Item | Price: 920 |-| Name: Item | Price: 1000
|
|
DAY: 10 | Name: Item | Price: 910 |-| Name: Item | Price: 1000
|
|
DAY: 11 | Name: Item | Price: 900 |-| Name: Item | Price: 1000
|
|
DAY: 12 | Name: Item | Price: 890 |-| Name: Item | Price: 1000
|
|
DAY: 13 | Name: Item | Price: 880 |-| Name: Item | Price: 1000
|
|
DAY: 14 | Name: Item | Price: 870 |-| Name: Item | Price: 1000
|
|
DAY: 15 | Name: Item | Price: 860 |-| Name: Item | Price: 1000
|
|
```
|
|
<!-- .element: class="fragment fade-in" -->
|
|
<!-- .slide: style="font-size: 0.72em" -->
|
|
___
|
|
|
|
## Ecerice 1
|
|
|
|
* <!-- .element: class="fragment fade-in" --> Go into directory <code>Ship</code> and implement <code>DecoratedCargo</code>:
|
|
* <!-- .element: class="fragment fade-in" --> It should take a <code>std::unique_ptr<Cargo></code> and has protected getter to this field.
|
|
* <!-- .element: class="fragment fade-in" --> Implement <code>Vunreable</code> class:
|
|
* <!-- .element: class="fragment fade-in" --> It should inherit from <code>TimeObserver</code> and <code>DecoratedCargo</code>
|
|
* <!-- .element: class="fragment fade-in" --> It should take additional parameters in C'tor: <code>Time</code>, <code>durability</code> and <code>maxDurability</code>
|
|
* <!-- .element: class="fragment fade-in" --> It should simulate time elapsing. Every day should subtract durability
|
|
* <!-- .element: class="fragment fade-in" --> It should return price back on current durability of cargo
|
|
|
|
___
|
|
|
|
## Exercise 2
|
|
|
|
* <!-- .element: class="fragment fade-in" --> Implement <code>Valuable</code> class:
|
|
* <!-- .element: class="fragment fade-in" --> It should inherit from <code>DecoratedCargo</code>
|
|
* <!-- .element: class="fragment fade-in" --> it should be a template that takes <code>enum</code> type of value
|
|
* <!-- .element: class="fragment fade-in" --> It should return value based on type (cast it to enum and multiply by current value)
|
|
* <!-- .element: class="fragment fade-in" --> Try to compile code form <code>main.cpp</code>
|
|
* <!-- .element: class="fragment fade-in" --> You may have some trouble with running code if you don't write a code carefully :) think where is a problem.
|