pythondesign-patterns

design pattern with Python -> abstract factory


I have implemented the abstract factory design pattern with Python and I see that it gives me the following error. this is my code :


"""
Abstract Factory
- Abstract Factory Pattern serves to provide 
    an interface for creating related/dependent 
    objects without need to specify their actual class

Car => Benz, Bmw => Suv, Coupe
benz suv = gla
bmw suv => x1
benz coupe => cls bmw coupe =>m2
"""

from abc import ABC, abstractmethod


class Car(ABC): # Abstract Factory
    @abstractmethod
    def call_suv(self):
        pass

    @abstractmethod
    def call_coupe(self):
        pass


class Benz(Car): # Concrete Factory 1
    def call_suv(self):
        return Gla

    def call_coupe(self):
        return Cls


class Bmw(Car): # Concrete Factory 2
    def call_suv(self):
        return X1

    def call_coupe(self):
        return M2


class Suv(ABC): # Abstract Product 1
    @abstractmethod
    def create_suv(self):
        pass


class Coupe(ABC): # Abstract Product 2
    @abstractmethod
    def create_coupe(self):
        pass


class Gla(Suv): # Product 1-1
    def create_suv(self):
        print(f" Benz + suv => Gla") 


class X1(Suv): # Product 2-1
    def create_suv(self):
        print(f" Bmw + suv => X1") 


class M2(Coupe): # Product 2-2
    def create_coupe(self):
        print(f" Bmw + coupe => M2") 


class Cls(Coupe):# Product 1-2
    def create_coupe(self):
        print(f" Benz + coupe => Cls") 


def client_suv(order): #client
    brand = {"bmw": Bmw, "benz": Benz}
    result = brand[order]().call_suv()
    result.create_suv()

def client_coupe(order):#client
    brand = {"bmw": Bmw, "benz": Benz}
    result = brand[order]().call_coupe()
    result.create_coupe()

client_coupe('benz')

and error :

❯ python abstract_factory.py                                                                                 ─╯
Traceback (most recent call last):
File "/Users/hmidreza/Desktop/proj/design pattern/abstract_factory.py", line 84, in \<module\>
client_coupe('benz')
File "/Users/hmidreza/Desktop/proj/design pattern/abstract_factory.py", line 82, in client_coupe
result.create_coupe()
TypeError: Cls.create_coupe() missing 1 required positional argument: 'self'

Solution

  • The issue arises because the call_coupe() method of the Benz and Bmw classes is returning the class itself (e.g., return Cls), not an instance of the class. So, this is why when you are calling create_coupe() it calls it as a static method.

    To solve the problem, you need to return class instances instead (e.g. return Cls())

    so the correct code could be :

    """
    Abstract Factory
    - Abstract Factory Pattern serves to provide
        an interface for creating related/dependent
        objects without need to specify their actual class
    
    Car => Benz, Bmw => Suv, Coupe
    benz suv = gla
    bmw suv => x1
    benz coupe => cls bmw coupe =>m2
    """
    
    from abc import ABC, abstractmethod
    
    
    class Car(ABC): # Abstract Factory
        @abstractmethod
        def call_suv(self):
            pass
    
        @abstractmethod
        def call_coupe(self):
            pass
    
    
    class Benz(Car): # Concrete Factory 1
        def call_suv(self):
            return Gla()
    
        def call_coupe(self):
            return Cls()
    
    
    class Bmw(Car): # Concrete Factory 2
        def call_suv(self):
            return X1()
    
        def call_coupe(self):
            return M2()
    
    
    class Suv(ABC): # Abstract Product 1
        @abstractmethod
        def create_suv(self):
            pass
    
    
    class Coupe(ABC): # Abstract Product 2
        @abstractmethod
        def create_coupe(self):
            pass
    
    
    class Gla(Suv): # Product 1-1
        def create_suv(self):
            print(f" Benz + suv => Gla")
    
    
    class X1(Suv): # Product 2-1
        def create_suv(self):
            print(f" Bmw + suv => X1")
    
    
    class M2(Coupe): # Product 2-2
        def create_coupe(self):
            print(f" Bmw + coupe => M2")
    
    
    class Cls(Coupe):# Product 1-2
        def create_coupe(self):
            print(f" Benz + coupe => Cls")
    
    
    def client_suv(order): #client
        brand = {"bmw": Bmw, "benz": Benz}
        result = brand[order]().call_suv()
        result.create_suv()
    
    def client_coupe(order):#client
        brand = {"bmw": Bmw, "benz": Benz}
        result = brand[order]().call_coupe()
        result.create_coupe()
    
    client_coupe('benz')