Factory 패턴

팩토리 메서드 패턴(Factory method pattern)은 객체지향 디자인 패턴이다. Factory method는 부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며. 자식(하위) 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴이기도 하다.

장점

싱글톤 패턴 : static을 사용한 효과로 객체를 생성하지 않고도 패턴을 사용가능.

예제

피자 가게에서 피자를 주문하고 그 가격을 출력해주는 예제

객체 생성 로직을 어디서 하는가 ?

Factory 패턴을 사용하지 않은 예제

void main(){
	var userSelectedPizza = PizzaType.HamMushroom;
	Pizza pizza;
	switch (userSelectedPizza){
		case PizzaType.HamMushroom;
			pizza = HamAndMushroomPizza();
			break;
		case PizzaType.Deluxe;
			pizza = DeluxePizza();
			break;
		case PizzaType.Seafood;
			pizza = SeafoodPizza();
			break;
	}
	print(pizza.getPrice());
}
// 피자 종류
enum PizzaType { HamMushroom, Deluxe, Seafood }

abstract class Pizza{
	double getPrice();
}

class HamAndMushroomPizza implements Pizza{
	double price = 10.5;
	@override
	double getPrice(){
		return price;
	}
}

class DeluxePizza implements Pizza{
	double price = 5.5;
	@override
	double getPrice(){
		return price;
	}
}

class SeafoodPizza implements Pizza{
	double price = 7.8;
	@override
	double getPrice(){
		return price;
	}
}

Factory 패턴을 사용한 예제

void main(){
	var userSelectedPizza = PizzaType.HamMushroom;
	print(Pizza.pizzaFactory(userSelectedPizza).getPrice());
}
// 피자 종류
enum PizzaType { HamMushroom, Deluxe, Seafood }

abstract class Pizza{
	double getPrice();
	// 팩토리 패턴
	static pizzaFactory(PizzaType type){
		switch (userSelectedPizza){
		case PizzaType.HamMushroom;
			return HamAndMushroomPizza();
			break;
		case PizzaType.Deluxe;
			return DeluxePizza();
			break;
		case PizzaType.Seafood;
			return SeafoodPizza();
			break;
		}
	}
}

class HamAndMushroomPizza implements Pizza{
	double price = 10.5;
	@override
	double getPrice(){
		return price;
	}
}

class DeluxePizza implements Pizza{
	double price = 5.5;
	@override
	double getPrice(){
		return price;
	}
}

class SeafoodPizza implements Pizza{
	double price = 7.8;
	@override
	double getPrice(){
		return price;
	}
}

로직 변경

DeluxePizza 객체 생성할때 orderNumber가 필요하다고 수정

class DeluxePizza implements Pizza{
	double price = 5.5;
	String orderNumber;
	DeluxePizza(this.orderNumber);
	@override
	double getPrice(){
		return price;
	}
}

Factory 패턴을 사용하지 않은 예제

void main(){
	var userSelectedPizza = PizzaType.HamMushroom;
	Pizza pizza;
	var orderNumber = '1234';
	switch (userSelectedPizza){
		case PizzaType.HamMushroom;
			pizza = HamAndMushroomPizza();
			break;
		case PizzaType.Deluxe;
			pizza = DeluxePizza(orderNumber);
			break;
		case PizzaType.Seafood;
			pizza = SeafoodPizza();
			break;
	}
	print(pizza.getPrice());
}

Factory 패턴을 사용한 예제

void main(){
	var userSelectedPizza = PizzaType.HamMushroom;
	String orderNumber = '1234';
	print(Pizza.pizzaFactory(userSelectedPizza,orderNumber).getPrice());
}
// 피자 종류
enum PizzaType { HamMushroom, Deluxe, Seafood }

abstract class Pizza{
	double getPrice();
	// 팩토리 패턴
	static pizzaFactory(PizzaType type, String orderNumber){
		switch (userSelectedPizza){
		case PizzaType.HamMushroom;
			return HamAndMushroomPizza();
			break;
		case PizzaType.Deluxe;
			return DeluxePizza(orderNumber);
			break;
		case PizzaType.Seafood;
			return SeafoodPizza();
			break;
		}
	}
}

Factory 패턴을 사용한 예제에서 Map 타입으로 데이터 넘겨주기

void main(){
	var userSelectedPizza = PizzaType.HamMushroom;
	String orderNumber = '1234';
	Map<String, dynamic> json = {
		'type': PizzaType.HamMushroom,
		'orderNumber' : '1234',
	}
	print(Pizza.pizzaFactory(json).getPrice());
}
// 피자 종류
enum PizzaType { HamMushroom, Deluxe, Seafood }

abstract class Pizza{
	double getPrice();
	// 팩토리 패턴
	static pizzaFactory(Map<String, dynamic> json){
		switch (json['type'] as PizzaType){
		case PizzaType.HamMushroom;
			return HamAndMushroomPizza();
			break;
		case PizzaType.Deluxe;
			return DeluxePizza(json['orderNumber'] as String);
			break;
		case PizzaType.Seafood;
			return SeafoodPizza();
			break;
		}
	}
}

Factory 패턴을 사용한 예제에서 Map 타입으로 데이터 넘겨줄때 Factory 타입으로 리턴

void main(){
	var userSelectedPizza = PizzaType.HamMushroom;
	String orderNumber = '1234';
	Map<String, dynamic> json = {
		'type': PizzaType.HamMushroom,
		'orderNumber' : '1234',
	}
	print(Pizza.fromJson(json).getPrice());
}
// 피자 종류
enum PizzaType { HamMushroom, Deluxe, Seafood }

abstract class Pizza{
	double getPrice();
	// 팩토리 패턴
	Factory Pizza.fromJson(Map<String, dynamic> json){
		switch (json['type'] as PizzaType){
		case PizzaType.HamMushroom;
			return HamAndMushroomPizza();
			break;
		case PizzaType.Deluxe;
			return DeluxePizza(json['orderNumber'] as String);
			break;
		case PizzaType.Seafood;
			return SeafoodPizza();
			break;
		default:
			return SeafoodPizza();
		}
	}
}

참고

https://www.youtube.com/watch?v=ZikfiBnFMk8 

 

728x90

'Study > Flutter' 카테고리의 다른 글

[Flutter] Provider pattern (bloc -> provider )  (0) 2021.06.16
[Flutter] Stateful widget  (0) 2021.06.14
[UI초급] Container, materialApp, Scaffold  (0) 2021.06.07

factory

factory는 새로운 인스턴스를 생성하고 싶지 않을 때 사용하는 생성자이다. 이와 같은 개념은 새로운 게 아니다. 소프트웨어 디자인 패턴 중 '싱글톤 패턴'을 따른 것이다.

Singleton 패턴

전역 변수를 사용하지 않고 객체를 하나만 생성 하도록 하며, 생성된 객체를 어디에서든지 참조할 수 있도록 하는 패턴

싱글톤 패턴의 사용하는 이유

메모리 측면

최초 한번의 new 연산자를 통해서 고정된 메모리 영역을 사용하기 때문에 추후 해당 객체에 접근할 때 메모리 낭비를 방지

이미 생성된 인스턴스를 활용하니 속도 측면에서도 이점

데이터 공유가 쉽다

싱글톤 인스턴스가 전역으로 사용되는 인스턴스이기 때문에 다른 클래스의 인스턴스들이 접근하여 사용할 수 있다

도메인 관점에서 인스턴스가 한 개만 존재하는 것을 보증하고 싶은 경우 싱글톤 패턴을 사용

factory의 특징

  • 기존에 이미 생성된 인스턴스가 있다면 return 하여 재사용한다.
  • 하나의 클래스에서 하나의 인스턴스만 생성한다(싱글톤 패턴).
  • 서브 클래스 인스턴스를 리턴할 때 사용할 수 있다.
  • Factory constructors 에서는 this 에 접근할 수 없다.

factory는 '클래스와 같은 타입의 인스턴스' 또는 '메서드를 구현하는 인스턴스'를 리턴하기만 하면 된다. 이렇게 생성된 인스턴스는기존에 생성된 인스턴스가 아니라면 새롭게 생성되고, 기존 인스턴스가 있다면 기존 것을 리턴한다.

factory 보단 warehouse 창고의 의미와 유사하다.

실사용 예

class NewsArticle {
  final String title, description, urlToImage, url;

  NewsArticle({this.title, this.description, this.urlToImage, this.url});

  factory NewsArticle.fromJSON(Map<String, dynamic> json) {
    return NewsArticle(
      title: json["title"],
      description: json["description"],
      urlToImage: json["urlToImage"],
      url: json["url"],
    );
  }
}
class AccountModel {
  AccountModel({
    this.avatar,
    this.id,
    this.iso6391,
    this.iso31661,
    this.name,
    this.includeAdult,
    this.username,
  });

  Avatar? avatar;
  int? id;
  String? iso6391;
  String? iso31661;
  String? name;
  bool? includeAdult;
  String? username;

  factory AccountModel.fromJson(Map<String, dynamic> json) => AccountModel(
        avatar: Avatar.fromJson(json["avatar"]),
        id: json["id"],
        iso6391: json["iso_639_1"],
        iso31661: json["iso_3166_1"],
        name: json["name"],
        includeAdult: json["include_adult"],
        username: json["username"],
      );

  Map<String, dynamic> toJson() => {
        "avatar": avatar!.toJson(),
        "id": id,
        "iso_639_1": iso6391,
        "iso_3166_1": iso31661,
        "name": name,
        "include_adult": includeAdult,
        "username": username,
      };
}
class Logger {
  final String name;
  bool mute = false;

  // _cache is library-private, thanks to
  // the _ in front of its name.
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    return _cache.putIfAbsent(
        name, () => Logger._internal(name));
  }

  factory Logger.fromJson(Map<String, Object> json) {
    return Logger(json['name'].toString());
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}
728x90

'Study > Dart' 카테고리의 다른 글

[Dart] future, async, await, 실행순서  (0) 2021.06.15
[Dart] const 와 final 이해하기  (0) 2021.06.15
[Dart] Future, Isolate  (0) 2021.06.08
[Dart] 상속을 쓰는 이유  (0) 2021.06.07
[Dart] 상속  (0) 2021.06.07

+ Recent posts