Hello again!
In my last post, I was showing you a basic example on how to implement and use the "Abstract Factory" pattern.
This time, it is Builder's patterns turn. I will describe the intent, and a simple use case where it naturally fits well (I hope).
Intent:
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
As an example is best than tones of lines, lets create a requirement:
"We need to create a small representation on how Ice creams will be built, and who is going to deal with the specifics of how to create/handle ice creams"
The code that uses the builder pattern to solve the requirement would look like this:
import abc
class InvalidIceCreamException(Exception):
pass
class IceCreamChashier:
def __init__(self):
self._ice_cream_builder = None
def construct(self, builder):
self._ice_cream_builder = builder
self._ice_cream_builder.build_type()
self._ice_cream_builder.build_flavors()
class IceCreamBuilder(metaclass=abc.ABCMeta):
def __init__(self):
self._ice_cream = IceCream()
@abc.abstractmethod
def build_type(self):
pass
@abc.abstractmethod
def build_flavors(self):
pass
@property
def ice_cream(self):
return self._ice_cream
@property
def ice_type(self):
return self.ice_cream.inner_type
@property
def flavors(self):
return self.ice_cream.list_flavors()
class IceCream(object):
GELATO = 'gelato'
CONE = 'cone'
SORBET = 'sorbet'
DONDURMA = 'dondurma'
TYPES = [GELATO, CONE, SORBET, DONDURMA]
def __init__(self):
self._type = None
self._flavors = set()
@property
def inner_type(self):
return self._type
def list_flavors(self):
return self._flavors
def set_type(self, ice_type):
if ice_type not in self.TYPES:
raise InvalidIceCreamException("This is an invalid icecream!")
self._type = ice_type
def set_flavor(self, flavor):
self._flavors.add(flavor)
class VanillaGelatoIceCreamBuilder(IceCreamBuilder):
def build_type(self):
self._ice_cream.set_type(IceCream.GELATO)
def build_flavors(self):
self._ice_cream.set_flavor('vanilla')
self._ice_cream.set_flavor('chocolate') #added just because... yes! Internal politics.
def main():
vanillaBuilder = VanillaGelatoIceCreamBuilder()
cashier = IceCreamChashier()
cashier.construct(vanillaBuilder)
print('Type of ice cream: {}'.format(vanillaBuilder.ice_type))
print('Flavors of ice cream: {}'.format(vanillaBuilder.flavors))
if __name__ == "__main__":
main()
So we can see that the complex object (IceCream) is hidden in the IceCreamBuilder abstraction, and we provide a small API to access to its main data, which is the ice cream type, and the flavors needed
Thats it!!
No hay comentarios:
Publicar un comentario