Featured image of post CP2 - Comparison between Factories: Simple Factory & Factory Method & Abstract Factory - Design Pattern From Simple Things

CP2 - Comparison between Factories: Simple Factory & Factory Method & Abstract Factory - Design Pattern From Simple Things

Simple Factory is da best, Factory Method and Abstract Factory are cumbersome, complicated and stupid?

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, but it’s not a member of the GoF family. I’ve talked about it before.

vending machine

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.

vending machine method

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 productRegularBeverage,DietBeverage,RegularSnack,DietSnack will be returned.

abstract vending machine

Why use Vending Machine?

It makes generating the products RegularBeverage, DietBeverage easier!

Why use Vending Machine Method?

Question: Can you edit the product classesBeverage,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 subclassesRegularVendingMachine,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 methodsdef 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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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:

1
2
{'type': <class 'RegularBeverage'>, 'burp_sound': 'BURP'}
{'type': <class 'DietBeverage'>, 'burp_sound': 'Diet - BURP'}

When to use Vending Machine Method?

Input:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
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:

1
2
{'type': <class 'RegularBeverage'>, 'burp_sound': 'BURP'}
{'type': <class 'DietBeverage'>, 'burp_sound': 'Diet - BURP'}

When to use Abstract Vending Machine?

Input:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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:

1
2
3
4
5
6
7
8
{'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?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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

How to implement Vending Machine Method?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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

How to implement Abstract Vending Machine?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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

Made with the laziness šŸ¦„
by a busy guy