# Creational Patterns

## Factory pattern

### Simple Factory

> Without factory

```python

    class Mercedes(object):
        def __repr__(self):
            return "Mercedes-Benz"
    
    class BMW(object):
        def __repr__(self):
            return "BMW"
            
mercedes = Mercedes()
bmw = BMW()
```

> With simple factory

```python
class SimpleCarFactory(object):
    @staticmethod
    def product_car(name):
        if name == 'mb':
            return Mercedes()
        elif name == 'bmw':
            return BMW()
            
c1 = SimpleCarFactory.product_car('mb')
c2 = SimpleCarFactory.product_car('bmw')
```

### Factory Method

Use abstract factory methode to add flexibility

```python
#coding=utf-8
import abc

class AbstractFactory(object):

    __metaclass__ = abc.ABCMeta

 @abc.abstractmethod
    def product_car(self):
        pass

class MercedesFactory(AbstractFactory):

    def product_car(self):
        return Mercedes()

class BMWFactory(AbstractFactory):
    def product_car(self):
        return BMW()
        
c1 = MercedesFactory().product_car()
c2 = BMWFactory().product_car()
```

### Abstract factory

Now let's make it better, we can produce SUV or normal car

```python
#coding=utf-8
import abc

# 两种小汽车
class Mercedes_C63(object):
    def __repr__(self):
        return "Mercedes-Benz: C63"

class BMW_M3(object):
 
    def __repr__(self):
        return "BMW: M3"

class Mercedes_G63(object):
    def __repr__(self):
        return "Mercedes-Benz: G63"

class BMW_X5(object):
 
    def __repr__(self):
        return "BMW: X5"

class AbstractFactory(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def product_car(self):
        pass

    @abc.abstractmethod
    def product_suv(self):
        pass

class MercedesFactory(AbstractFactory):
  
    def product_car(self):
        return Mercedes_C63()

    def product_suv(self):
        return Mercedes_G63()

class BMWFactory(AbstractFactory):

    def product_car(self):
        return BMW_M3()

    def product_suv(self):
        return BMW_X5()
        
c1 = MercedesFactory().product_car()
s1 = MercedesFactory().product_suv()
print(c1, s1)
s2 = BMWFactory().product_suv()
c2 = BMWFactory().product_car()
print(c2, s2)
```

### Reference (Chinese)

{% embed url="<https://segmentfault.com/a/1190000013053013>" %}

## Personal example

Read data from csv and filter on it based on requirements

```python
import hashlib
import abc
from collections import namedtuple

# Build data type
basic_cols = ['a','b','c'... ,'hash_d=id']
fields = " ".join(basic_cols)
Data = namedtuple('Data',fields,defaults=""* len(fields))



class Datafactory:
	__metaclass__ = abc.ABCMeta
	source = []
	def __init__(self,file_name):
	    if self.source==[]:
		print("Reading data...")
		with open(file_name,encoding='utf-8') as file:
	            file_iter = iter(file)
		    # Jump first line
		    _ = next(file_iter)
		    for line in file_iter:
	                each_ine = line.strip("\n").split(";")+['']
			self.source.append(Data(*each_line))
			print("Finish")
			print("Add hash_id ...")
			self.source = list(map(self.create_hash_id,self.source))
	@staticmethod
	def create_hash_id(each):
		text = "".join(x.replace(" ","") for x in each._asdict().values())
		return each._replace(hash_id = hashlib.sha256(text.encode('utf-8').hexdigest())	
	
	@abc.abstractmethod
	def produce_data(self):
		pass


class D1_Factory(DataFactory):
	def __init__(self,file_name):
		super().__init__(file_name)
		print("Apply D1 filter...")
		self.d1_data = list(filter(self.apply_filter,self.source))	
		print("Done")

	@staticmethod
	def apply_filter(e):
		return (e.a=='xxx' and e.b in [1,24] and ..)
	
	def produce_data(self):
		return pd.DataFrame(self.d1_data,columns = Data._fields)
	
class C1_Factory(DataFactory):
	def __init__(self,file_name):
		super().__init__(file_name)
		print("Apply C1 filter...")
		self.c1_data= list(filter(self.apply_filter,self.source))	
		print("Done")

	@staticmethod
	def apply_filter(e):
		return (e.c=='c1')
	
	def produce_data(self):
		return pd.DataFrame(self.c1_data,columns = Data._fields)


D1_data = D1_Factory('data.csv').produce_data()
C1_data = C1_Factory('data.csv').produce_data()
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zeliang-yao.gitbook.io/my-note-zeliang-yao/useful/design-patterns/creational-patterns.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
