Уведомления

Группа в Telegram: @pythonsu

#1 Март 9, 2019 14:44:51

zlodiak
От: Россия
Зарегистрирован: 2014-01-19
Сообщения: 159
Репутация: +  0  -
Профиль   Адрес электронной почты  

Зачем усложняется фабричный метод?

В интернетах и в учебниках при объяснении работы паттерна “фабричный метод” используется приблизительно такой пример. его особенность в том, что класс-наследник переопределяет метод родителя, отвечающий за создание объектов(отсюда и название паттерна):

 class Door:
    def __init__(self, weight):
        self.weight = weight
    def __str__(self):
        return str(self.weight)
class Brick:
    def __init__(self, weight):
        self.weight = weight
    def __str__(self):
        return str(self.weight)        
class FactoryMethod:
    def create(self, weight, type_):
        pass
class Creator(FactoryMethod):
    def create(self, type_, weight):
        if type_ == 'door':
            print('door with weight: ', Door(weight))
        else:
            print('brick with weight: ', Brick(weight))
c = Creator()
c.create('brick', 10)
c.create('door', 100)

Но мне кажется, что незачем писать лишний код и вышеприведённый пример можно переписать короче:
 class Door:
    def __init__(self, weight):
        self.weight = weight
    def __str__(self):
        return str(self.weight)
class Brick:
    def __init__(self, weight):
        self.weight = weight
    def __str__(self):
        return str(self.weight)        
class Creator:
    def create(self, type_, weight):
        if type_ == 'door':
            print('door with weight: ', Door(weight))
        else:
            print('brick with weight: ', Brick(weight))
c = Creator()
c.create('brick', 10)
c.create('door', 100)

Скажите пожалуйста, прав ли я? не потеряла ли вторая реализация что-то важное? почему же везде приводится именно первый пример?

Офлайн

#2 Март 9, 2019 15:22:44

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

Зачем усложняется фабричный метод?

zlodiak
В очередной раз мы возвращаемся к особенностям питона. Понимаете, многие (да почти все) паттерны актуальны только для статически типизированных языков, для С++, Java, С# и пр. Если вы пишите на Java, вы должны указать компилятору какие атрибуты каких типов содержит объект. FactoryMethod нужен для того, чтобы иметь родительский для всех реализаций тип, чтобы не привязывать код к конкретным реализациям.

так плохо

 class Foo:
    def __init__(self, creator: ConsoleLoggerCreator):
         self.creator = creator
class Bar:
    def __init__(self, creator: FileLoggerCreator):
         self.creator = creator

а так лучше
 class ConsoleLoggerCreator(LoggerCreatorInteface):
    ...
class FileLoggerCreator(LoggerCreatorInteface):
   ...
  
class Foo:
    def __init__(self, creator: LoggerCreatorInteface):
         self.creator = creator
class Bar:
    def __init__(self, creator: LoggerCreatorInteface):
         self.creator = creator

Если хотите понять паттерны, забудьте про питон, он тут плохо подходит и только смущает. Повторю: солидная часть паттернов по сути решает проблемы связанные со статической типизацией.



Офлайн

#3 Март 10, 2019 00:51:17

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10024
Репутация: +  857  -
Профиль   Отправить e-mail  

Зачем усложняется фабричный метод?

Проходил по “банде четырёх” и другим разрозненным источникам шаблон фабричный метод.

Вообще, сначала писал на Java пример, так как там есть все синтаксические конструкции для ООП, а потом переводил на Python, Go, JavaScript.

Фабричный метод без параметра

  
#!/usr/bin/env python3
 
from abc import ABCMeta, abstractmethod
 
 
class UnitInterface(metaclass=ABCMeta):
 
    @abstractmethod
    def what(self):
        pass
 
 
class Creator(metaclass=ABCMeta):
 
    @abstractmethod
    def make_unit(self):
        pass
 
    def new_unit(self):
        return self.make_unit()
 
 
class Dog(UnitInterface):
 
    def what(self):
        return 'dog'
 
 
class DogCreator(Creator):
 
    def make_unit(self):
        return Dog()
 
 
class Cat(UnitInterface):
 
    def what(self):
        return 'cat'
 
 
class CatCreator(Creator):
 
    def make_unit(self):
        return Cat()
 
 
def action(creator):
    unit = creator.new_unit()
    print('The {} is created.'.format(unit.what()))
 
 
def main():
    action(DogCreator())
    action(CatCreator())
 
if __name__ == '__main__':
    main()
 

Фабричный метод с параметром
  
#!/usr/bin/env python3
 
from abc import ABCMeta, abstractmethod
import enum
 
 
class UnitInterface(metaclass=ABCMeta):
 
    @abstractmethod
    def what(self):
        pass
 
 
class Dog(UnitInterface):
 
    def what(self):
        return 'dog'
 
 
class Cat(UnitInterface):
 
    def what(self):
        return 'cat'
 
 
class UnitTypes(enum.Enum):
    DOG = 0
    CAT = 1
 
 
class Creator:
 
    def make_unit(self, unit_type):
        if unit_type == UnitTypes.DOG:
            return Dog()
        elif unit_type == UnitTypes.CAT:
            return Cat()
        else:
            raise ValueError("unit type is unknown: " + str(unit_type))
 
 
def action(creator, unit_type):
    unit = creator.make_unit(unit_type)
    print('The {} is created.'.format(unit.what()))
 
 
def main():
    action(Creator(), UnitTypes.DOG)
    action(Creator(), UnitTypes.CAT)
 
if __name__ == '__main__':
    main()

Аналоги на Java

Фабричный метод с параметром
interface Unit {
String what();
}

class Dog implements Unit {
@Override
public String what() {
return "dog";
}
}

class Cat implements Unit {
@Override
public String what() {
return "cat";
}
}

enum UnitTypes {
DOG,
CAT
}

class Creator {
public Unit makeUnit(UnitTypes unitType) throws Exception {
if (unitType == UnitTypes.DOG) {
return new Dog();
} else if (unitType == UnitTypes.CAT) {
return new Cat();
} else {
throw new Exception("unit type is unknown: " + unitType);
}
};
}

class T {
public static void main(String args[]) {
action(new Creator(), UnitTypes.DOG);
action(new Creator(), UnitTypes.CAT);
}
private static void action(Creator creator, UnitTypes unitType) {
try {
Unit unit = creator.makeUnit(unitType);
System.out.printf("The %s is created.\n", unit.what());
} catch (Exception e) {
System.out.println(e);
}
}
}

Фабричный метод без параметра
interface Unit {
String what();
}

abstract class Creator {
public abstract Unit makeUnit();
public Unit newUnit() {
return makeUnit();
};
}

class Dog implements Unit {
@Override
public String what() {
return "dog";
}
}

class DogCreator extends Creator {
@Override
public Unit makeUnit() {
return new Dog();
}
}

class Cat implements Unit {
@Override
public String what() {
return "cat";
}
}

class CatCreator extends Creator {
@Override
public Unit makeUnit() {
return new Cat();
}
}

class T {
public static void main(String args[]) {
action(new DogCreator());
action(new CatCreator());
}
private static void action(Creator creator) {
Unit unit = creator.newUnit();
System.out.printf("The %s is created.\n", unit.what());
}
}


tags: oop pattern



Отредактировано py.user.next (Март 10, 2019 01:00:48)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version