Patrón Builder

El patrón Builder es un patrón de diseño creacional que te permite separar los pasos de creación de un objeto complejo de su representación.

El patrón Builder es un patrón de diseño creacional cuyo objetivo principal es separar el proceso de construcción de un objeto complejo de su representación, lo que permite crear objetos con diferentes formas de representación.

Resumen

Intención

Separar un proceso de construcción complejo de su representación, de modo que el mismo proceso de construcción pueda crear diferentes representaciones.

Problema principal

En los sistemas de software, la creación de un objeto complejo suele constar de múltiples partes; la combinación de estas partes cambia a menudo, pero el algoritmo de combinación es relativamente estable.

Cuándo usarlo

Cuando algunos componentes básicos no cambian, pero su combinación cambia con frecuencia.

Cómo resolverlo

Separar las partes variables de las invariables.

Código clave

  • Constructor: crea y proporciona instancias.
  • Director: gestiona las dependencias de las instancias construidas y controla el proceso de construcción.

Ejemplos de aplicación

  • Ir a KFC: la hamburguesa, la Coca-Cola, las papas fritas, las alitas de pollo frito, etc. no cambian, pero su combinación cambia con frecuencia, generando diferentes “combos”.
  • En JavaStringBuilder。

Ventajas

  • Separa el proceso de construcción de la representación, lo que hace que el proceso de construcción sea más flexible y pueda construir diferentes representaciones.
  • Permite un mejor control del proceso de construcción y oculta los detalles concretos de construcción.
  • Alta reutilización del código: se puede reutilizar el mismo constructor en diferentes procesos de construcción.

Desventajas

  • Si el producto tiene pocas propiedades, el patrón Builder puede provocar redundancia de código.
  • Aumenta el número de clases y objetos del sistema.

Escenarios de uso

  • Cuando el objeto que se debe generar tiene una estructura interna compleja.
  • Cuando los atributos internos del objeto que se debe generar son interdependientes.

Notas

La diferencia con el patrón de fábrica es que el patrón Builder se centra más en el orden de ensamblaje de las piezas.

Estructura

El patrón Builder incluye los siguientes roles principales:

  • Producto (Product): el objeto complejo que se va a construir. La clase de producto normalmente contiene múltiples partes o atributos.

  • Constructor abstracto (Builder): define la interfaz abstracta para construir el producto, incluyendo los métodos para construir cada una de sus partes.

  • Constructor concreto (Concrete Builder): implementa la interfaz del constructor abstracto, determina concretamente cómo construir cada parte del producto y se encarga de devolver el producto finalmente construido.

  • Director (Director): se encarga de llamar a los métodos del constructor para construir el producto; el director no conoce el proceso de construcción específico, solo le importa el orden y la forma de construcción del producto.

Implementación

Supongamos un caso de negocio de una tienda de comida rápida, donde un combo típico puede ser una hamburguesa (Burger) y una bebida fría (Cold drink). La hamburguesa puede ser vegetariana (Veg Burger) o de pollo (Chicken Burger), y se envuelven en una caja de cartón. La bebida fría puede ser Coca-Cola (coke) o Pepsi (pepsi), y se sirven en botella.

Vamos a crear unaIteminterfaz e implementaciónItemde las clases de entidad de la interfaz, y una que represente el empaque de alimentosPackinginterfaz e implementaciónPackingde las clases de entidad de la interfaz. La hamburguesa se envuelve en una caja de cartón y la bebida fría se sirve en botella.

Luego creamos unaMealclase, conItemdeArrayListy una mediante la combinación deItempara crear diferentes tipos deMealobjetosMealBuilder。BuilderPatternDemola clase usaMealBuilderpara crear unMeal。

建造者模式的 UML 图

Paso 1

Cree una interfaz que represente los artículos de comida y el empaque de alimentos.

Item.java

public interface Item { public String name(); public Packing packing(); public float price(); }

Packing.java

public interface Packing { public String pack(); }

Paso 2

Cree clases de entidad que implementen la interfaz Packing.

Wrapper.java

public class Wrapper implements Packing { @Override public String pack() { return "Wrapper"; } }

Bottle.java

public class Bottle implements Packing { @Override public String pack() { return "Bottle"; } }

Paso 3

Cree una clase abstracta que implemente la interfaz Item; esta clase proporciona funcionalidad predeterminada.

Burger.java

public abstract class Burger implements Item { @Override public Packing packing() { return new Wrapper(); } @Override public abstract float price(); }

ColdDrink.java

public abstract class ColdDrink implements Item { @Override public Packing packing() { return new Bottle(); } @Override public abstract float price(); }

Paso 4

Cree clases de entidad que extiendan Burger y ColdDrink.

VegBurger.java

public class VegBurger extends Burger { @Override public float price() { return 25.0f; } @Override public String name() { return "Veg Burger"; } }

ChickenBurger.java

public class ChickenBurger extends Burger { @Override public float price() { return 50.5f; } @Override public String name() { return "Chicken Burger"; } }

Coke.java

public class Coke extends ColdDrink { @Override public float price() { return 30.0f; } @Override public String name() { return "Coke"; } }

Pepsi.java

public class Pepsi extends ColdDrink { @Override public float price() { return 35.0f; } @Override public String name() { return "Pepsi"; } }

Paso 5

Cree una clase Meal con los objetos Item definidos anteriormente.

Meal.java

import java.util.ArrayList; import java.util.List; public class Meal { private List<Item> items = new ArrayList<Item>(); public void addItem(Item item){ items.add(item); } public float getCost(){ float cost = 0.0f; for (Item item : items) { cost += item.price(); } return cost; } public void showItems(){ for (Item item : items) { System.out.print("Item : "+item.name()); System.out.print(", Packing : "+item.packing().pack()); System.out.println(", Price : "+item.price()); } } }

Paso 6

Cree una clase MealBuilder; la clase builder real es la responsable de crear objetos Meal.

MealBuilder.java

public class MealBuilder { public Meal prepareVegMeal (){ Meal meal = new Meal(); meal.addItem(new VegBurger()); meal.addItem(new Coke()); return meal; } public Meal prepareNonVegMeal (){ Meal meal = new Meal(); meal.addItem(new ChickenBurger()); meal.addItem(new Pepsi()); return meal; } }

Paso 7

BuiderPatternDemo usa MealBuilder para demostrar el patrón Builder.

BuilderPatternDemo.java

public class BuilderPatternDemo { public static void main(String[] args) { MealBuilder mealBuilder = new MealBuilder(); Meal vegMeal = mealBuilder.prepareVegMeal(); System.out.println("Veg Meal"); vegMeal.showItems(); System.out.println("Total Cost: " +vegMeal.getCost()); Meal nonVegMeal = mealBuilder.prepareNonVegMeal(); System.out.println("\n\nNon-Veg Meal"); nonVegMeal.showItems(); System.out.println("Total Cost: " +nonVegMeal.getCost()); } }

Paso 8

Ejecute el programa y observe el resultado:

Veg Meal
Item : Veg Burger, Packing : Wrapper, Price : 25.0
Item : Coke, Packing : Bottle, Price : 30.0
Total Cost: 55.0


Non-Veg Meal
Item : Chicken Burger, Packing : Wrapper, Price : 50.5
Item : Pepsi, Packing : Bottle, Price : 35.0
Total Cost: 85.5

Artículos relacionados

Otras extensiones