![팩토리 메서드](/images/patterns/cards/factory-method-mini.png?id=72619e9527893374b98a5913779ac167)
루비로 작성된 팩토리 메서드
팩토리 메서드는 제품 객체들의 구상 클래스들을 지정하지 않고 해당 제품 객체들을 생성할 수 있도록 하는 생성 디자인 패턴입니다.
팩토리 메서드는 메서드를 정의하며, 이 메서드는 직접 생성자 호출(new
연산자)을 사용하여 객체를 생성하는 대신 객체 생성에 사용되여야 합니다. 자식 클래스들은 이 메서드를 오버라이드하여 생성될 객체들의 클래스를 변경할 수 있습니다.
다양한 팩토리 패턴들과 개념들의 차이점을 이해하지 못하셨다면 팩토리 비교를 읽어보세요.
복잡도:
인기도:
사용 사례들: 팩토리 메서드 패턴은 루비 코드에서 널리 사용되며 코드에 높은 수준의 유연성을 제공해야 할 때 매우 유용합니다.
식별: 팩토리 메서드는 구상 클래스들로부터 객체들을 생성하는 생성 메서드들로 인식될 수 있습니다. 구상 클래스들은 객체 생성 중에 사용되지만 팩토리 메서드들의 반환 유형은 일반적으로 추상 클래스 또는 인터페이스로 선언됩니다.
개념적인 예시
이 예시는 팩토리 메서드의 구조를 보여주고 다음 질문에 중점을 둡니다:
- 패턴은 어떤 클래스들로 구성되어 있나요?
- 이 클래스들은 어떤 역할을 하나요?
- 패턴의 요소들은 어떻게 서로 연관되어 있나요?
main.rb: 개념적인 예시
# The Creator class declares the factory method that is supposed to return an
# object of a Product class. The Creator's subclasses usually provide the
# implementation of this method.
class Creator
# Note that the Creator may also provide some default implementation of the
# factory method.
def factory_method
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
# Also note that, despite its name, the Creator's primary responsibility is
# not creating products. Usually, it contains some core business logic that
# relies on Product objects, returned by the factory method. Subclasses can
# indirectly change that business logic by overriding the factory method and
# returning a different type of product from it.
def some_operation
# Call the factory method to create a Product object.
product = factory_method
# Now, use the product.
"Creator: The same creator's code has just worked with #{product.operation}"
end
end
# Concrete Creators override the factory method in order to change the resulting
# product's type.
class ConcreteCreator1 < Creator
# Note that the signature of the method still uses the abstract product type,
# even though the concrete product is actually returned from the method. This
# way the Creator can stay independent of concrete product classes.
def factory_method
ConcreteProduct1.new
end
end
class ConcreteCreator2 < Creator
# @return [ConcreteProduct2]
def factory_method
ConcreteProduct2.new
end
end
# The Product interface declares the operations that all concrete products must
# implement.
class Product
# return [String]
def operation
raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
end
end
# Concrete Products provide various implementations of the Product interface.
class ConcreteProduct1 < Product
# @return [String]
def operation
'{Result of the ConcreteProduct1}'
end
end
class ConcreteProduct2 < Product
# @return [String]
def operation
'{Result of the ConcreteProduct2}'
end
end
# The client code works with an instance of a concrete creator, albeit through
# its base interface. As long as the client keeps working with the creator via
# the base interface, you can pass it any creator's subclass.
def client_code(creator)
print "Client: I'm not aware of the creator's class, but it still works.\n"\
"#{creator.some_operation}"
end
puts 'App: Launched with the ConcreteCreator1.'
client_code(ConcreteCreator1.new)
puts "\n\n"
puts 'App: Launched with the ConcreteCreator2.'
client_code(ConcreteCreator2.new)
output.txt: 실행 결과
App: Launched with the ConcreteCreator1.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct1}
App: Launched with the ConcreteCreator2.
Client: I'm not aware of the creator's class, but it still works.
Creator: The same creator's code has just worked with {Result of the ConcreteProduct2}