---
title: "CP2 - Comparison between Factories: Simple Factory & Factory Method & Abstract Factory - Design Pattern From Simple Things"
description: "Simple Factory is da best, Factory Method and Abstract Factory are cumbersome, complicated and stupid?"
pubDate: "2022-11-11"
lang: "en"
slug: "cp2-comparison-between-factories-simple-factory-factory-method-abstract-factory-design-pattern-from-simple-things"
url: "https://hoangyell.com/cp2-comparison-between-factories-simple-factory-factory-method-abstract-factory-design-pattern-from-simple-things/"
author: "HoangYell"
categories: ["Software Craft"]
tags: ["design-patterns", "creational-patterns"]
heroImage: "https://raw.githubusercontent.com/HoangGeek/store/main/webp/2Isjr10.webp"
---

_Vending Machine Method (Factory Method) is a **creational** design pattern:_
🖤🤍🤍🤍🤍
_Abstract Vending Machine(Abstract Factory) is a **creational** design pattern:_
🖤🖤🤍🤍🤍

## What is Vending Machine(Simple Factory)?
It's a way to create:
- a class `Vending Machine` creating objects without requiring any concrete classes `RegularBeverage,DietBeverage`.

`Vending Machine` looks handsome and [famous](https://www.oreilly.com/library/view/head-first-design/0596007124/), but it's not a member of the [GoF](https://www.oreilly.com/library/view/design-patterns-elements/0201633612/) family. [I've talked about it before.](https://hoangyell.com/p/cp1-vending-machine-factory-design-pattern-from-simple-things/)

![Image](https://raw.githubusercontent.com/HoangGeek/store/main/webp/201276370-20e1642e-67e0-41d5-ad8f-1423ecef5a80.webp)

## What is Vending Machine Method(Factory Method)?
It's a way to create:
- a Parent(Super) class `Vending Machine`
  - with an abstractmethod `def create_beverage: return None` to generate the specific product.
  - with a common method `def show_info` to return the product's info
- Sub(Child/Inherited) classes `RegularVendingMachine, DietVendingMachine` will redefine what product `RegularBeverage(),DietBeverage()` will be returned.

![Image](https://raw.githubusercontent.com/HoangGeek/store/main/webp/201326839-c220b6f1-d53b-4e0b-8279-6dd0143fb347.webp)

## What is Abstract Vending Machine(Abstract Factory)?
>same as Machine Method(Factory Method), but it can generate many `beverage, snack` kind of products instead of only one `beverage`

It's a way to create:
- a Parent(Super) class `Vending Machine` defines abstractmethod(s) `def create_beverage: return None, def create_snack: return None` to generate the product.
- Sub(Child/Inherited) classes `RegularVendingMachine, DietVendingMachine` will redefine what product`RegularBeverage,DietBeverage,RegularSnack,DietSnack` will be returned.

![Image](https://raw.githubusercontent.com/HoangGeek/store/main/webp/201324030-2ed26c25-4907-479c-a292-0bdc6c1a69a4.webp)

## Why use Vending Machine?
It makes generating the products `RegularBeverage, DietBeverage`  easier!

## Why use Vending Machine Method?
**Question:** _Can you edit the product classes`Beverage,RegularBeverage,DietBeverage` (is it yours)?_

**Answer:** _Yes_
  - Just using Vending Machine is enough! It may require editing the product classes a bit, but it's nicer. Don't use Vending Machine Method if you don't really need it.

**Answer:** _No_
  - Okay, Vending Machine Method is helpful when you can't edit the product classes (it's not your classes, can't touch it).
  - Vending Machine Method lets a class defer (postpone, delay) instantiation to subclasses.
  - Your subclasses`RegularVendingMachine,DietVendingMachine,...` will:
    - inherit your superclass `VendingMachine`
    - redefines the generation method `def create_beverage` in its own way 
    - then subclasses generate products `RegularBeverage, DietBeverage, ...` that have common methods`def show_info` , properties of superclass without redefinition.

## Why use Abstract Vending Machine?
When you want to use Vending Machine Method, but you can not!
Because have more `Beverage, Snack` than one `Beverage(Regular,Diet)` kind of product need to be handled

When products are:
- `Beverage, Snack` can use Vending Machine Method
- `RegularBeverage, DietBeverage` can use Vending Machine Method
- `RegularSnack, DietSnack` can use Vending Machine Method

When products are:
- `RegularBeverage, DietBeverage, RegularSnack, DietSnack` can use Abstract Vending Machine

## When to use Vending Machine?

### Input:
```python
from abc import ABC, abstractmethod

class Beverage(ABC):
    @abstractmethod
    def make_burp(self):
        pass

    # Q:Can you edit the product classes? A:Yes.
    # Since this class can be edited, we add `def show_info` here for later use
    def show_info(self):
        info = {
            **self.__dict__,
            "type": type(self),
            "burp_sound": self.make_burp(),
        }
        return info

class RegularBeverage(Beverage):
    def make_burp(self):
        return "BURP"

class DietBeverage(Beverage):
    def make_burp(self):
        return "Diet - BURP"
```
### Expected Output:
```shell
{'type': <class 'RegularBeverage'>, 'burp_sound': 'BURP'}
{'type': <class 'DietBeverage'>, 'burp_sound': 'Diet - BURP'}
```

## When to use Vending Machine Method?

### Input:
```python
from abc import ABC, abstractmethod

class Beverage(ABC):
    @abstractmethod
    def make_burp(self):
        pass
    
    # Q:Can you edit the product classes? A:No.
    # Since this class is immutable, we can not add `def show_info` here, we have to find another way like, wrap from the outside!

class RegularBeverage(Beverage):
    def make_burp(self):
        return "BURP"

class DietBeverage(Beverage):
    def make_burp(self):
        return "Diet - BURP"
```
### Expected Output:
```shell
{'type': <class 'RegularBeverage'>, 'burp_sound': 'BURP'}
{'type': <class 'DietBeverage'>, 'burp_sound': 'Diet - BURP'}
```

## When to use Abstract Vending Machine?

### Input:
```python
from abc import ABC, abstractmethod

class Beverage(ABC):
    @abstractmethod
    def make_burp(self):
        pass

class Snack(ABC):
    @abstractmethod
    def make_thirsty(self):
        pass

class RegularBeverage(Beverage):
    def make_burp(self):
        return "BURP"

class RegularSnack(Snack):
    def make_thirsty(self):
        return "I'm thirsty"

class DietBeverage(Beverage):
    def make_burp(self):
        return "Diet - BURP"

class DietSnack(Snack):
    def make_thirsty(self):
        return "Diet - I'm thirsty"
```
### Expected Output:
```shell
{'type': <class 'RegularBeverage'>, 'burp_sound': 'BURP'}
       - "BURP"
{'type': <class 'RegularSnack'>, 'thirsty_sound': "I'm thirsty"}
       - "I'm thirsty"
{'type': <class 'DietBeverage'>, 'burp_sound': 'Diet - BURP'}
       - "Diet - BURP"
{'type': <class 'DietSnack'>, 'thirsty_sound': "Diet - I'm thirsty"}
       - "Diet - I'm thirsty"
```

## How to implement Vending Machine?

```python
class BeverageVendingMachine:
    def generate(self, beverage_type):
        if beverage_type == "Regular":
            return RegularBeverage()
        elif beverage_type == "Diet":
            return DietBeverage()

if __name__ == "__main__":
    for beverage_type in ("Regular", "Diet"):
        beverage = BeverageVendingMachine().generate(beverage_type)
        print(beverage.show_info())
```

[Source Code: Vending Machine](https://github.com/HoangYell/Design-Pattern-From-Simple-Things/blob/main/cp2_vending_machine.py)

## How to implement Vending Machine Method?
```python
class VendingMachine(ABC):
    @abstractmethod
    def create_beverage(self):
        pass

    def show_info(self):
        beverage = self.create_beverage()
        info = {
            **beverage.__dict__,
            "type": type(beverage),
            "burp_sound": beverage.make_burp(),
        }
        return info

class RegularVendingMachine(VendingMachine):
    def create_beverage(self):
        return RegularBeverage()

class DietVendingMachine(VendingMachine):
    def create_beverage(self):
        return DietBeverage()

if __name__ == "__main__":
    for vending_machine in (RegularVendingMachine(), DietVendingMachine()):
        print(vending_machine.show_info())
```

[Source Code: Vending Machine Method](https://github.com/HoangYell/Design-Pattern-From-Simple-Things/blob/main/cp2_vending_machine_method.py)

## How to implement Abstract Vending Machine?
```python
class AbstractVendingMachine(ABC):
    @abstractmethod
    def create_beverage(self):
        pass

    @abstractmethod
    def create_snack(self):
        pass

    def show_beverage_info(self):
        beverage = self.create_beverage()
        info = {
            **beverage.__dict__,
            "type": type(beverage),
            "burp_sound": beverage.make_burp(),
        }
        return info

    def show_snack_info(self):
        snack = self.create_snack()
        info = {
            **snack.__dict__,
            "type": type(snack),
            "thirsty_sound": snack.make_thirsty(),
        }
        return info

class RegularVendingMachine(AbstractVendingMachine):
    def create_beverage(self):
        return RegularBeverage()

    def create_snack(self):
        return RegularSnack()

class DietVendingMachine(AbstractVendingMachine):
    def create_beverage(self):
        return DietBeverage()

    def create_snack(self):
        return DietSnack()

if __name__ == "__main__":
    for vending_machine in (RegularVendingMachine(), DietVendingMachine()):
        beverage_vending_machine = vending_machine.create_beverage()
        print(vending_machine.show_beverage_info())
        print(f'       - "{beverage_vending_machine.make_burp()}"')
        snack_vending_machine = vending_machine.create_snack()
        print(vending_machine.show_snack_info())
        print(f'       - "{snack_vending_machine.make_thirsty()}"')
```

[Source Code: Abstract Vending Machine](https://github.com/HoangYell/Design-Pattern-From-Simple-Things/blob/main/cp2_abstract_vending_machine.py)
