---
id: 68e52994bc7ea2e3dec530a1
title: Step 23
challengeType: 20
dashedName: step-23
---

# --description--

Now you need a way to manage multiple discount strategies and find the best price.

Create a class named `DiscountEngine`. This class will manage all discount strategies and calculate the best price for a product.

Give it an `__init__` method that takes `self` and `strategies` as parameters, where `strategies` has a type hint of `list[DiscountStrategy]`. Using `list[DiscountStrategy]` specifies that the parameter is a list containing `DiscountStrategy` objects. The return type of the method should be `None`. Inside the `__init__` method, store `strategies` as an instance attribute.

# --hints--

You should create a class named `DiscountEngine`.

```js
({
  test: () => runPython(`assert _Node(_code).has_class("DiscountEngine")`)
})
```

Your `DiscountEngine` class should have an `__init__` method.

```js
({
  test: () => runPython(`assert _Node(_code).find_class("DiscountEngine").has_function("__init__")`)
})
```

Your `__init__` method should have parameters `self` and `strategies: list[DiscountStrategy]`.

```js
({
  test: () => runPython(`assert _Node(_code).find_class("DiscountEngine").find_function("__init__").has_args("self, strategies: list[DiscountStrategy]")`)
})
```

Your `__init__` method should have a return type of `None`.

```js
({
  test: () => runPython(`assert _Node(_code).find_class("DiscountEngine").find_function("__init__").has_returns("None")`)
})
```

You should assign `strategies` to `self.strategies` inside your `__init__` method.

```js
({
  test: () => runPython(`
    assert _Node(_code).find_class("DiscountEngine").find_function("__init__").has_stmt("self.strategies = strategies")
  `)
})
```

# --seed--

## --seed-contents--

```py
from abc import ABC, abstractmethod

class Product:
    def __init__(self, name: str, price: float) -> None:
        self.name = name
        self.price = price

    def __str__(self) -> str:
        return f'{self.name} - ${self.price}'

class DiscountStrategy(ABC):
    @abstractmethod
    def is_applicable(self, product: Product, user_tier: str) -> bool:
        pass

    @abstractmethod
    def apply_discount(self, product: Product) -> float:
        pass

class PercentageDiscount(DiscountStrategy):
    def __init__(self, percent: int) -> None:
        self.percent = percent

    def is_applicable(self, product: Product, user_tier: str) -> bool:
        return self.percent <= 70

    def apply_discount(self, product: Product) -> float:
        return product.price * (1 - self.percent / 100)

class FixedAmountDiscount(DiscountStrategy):
    def __init__(self, amount: int) -> None:
        self.amount = amount

    def is_applicable(self, product: Product, user_tier: str) -> bool:
        return product.price * 0.9 > self.amount

    def apply_discount(self, product: Product) -> float:
        return product.price - self.amount

class PremiumUserDiscount(DiscountStrategy):
    def is_applicable(self, product: Product, user_tier: str) -> bool:
        return user_tier.lower() == 'premium'

    def apply_discount(self, product: Product) -> float:
        return product.price * 0.8
--fcc-editable-region--

--fcc-editable-region--
product = Product('Wireless Mouse', 50.0)
print(product)

discount = PercentageDiscount(10)
print(discount.apply_discount(product))

fixed_discount = FixedAmountDiscount(5)
print(fixed_discount.apply_discount(product))
```
