Mire los patrones de diseño de Java de los 72 cambios de Monkey King: patrón de decorador

Escenarios de aplicación

JD.com, Tmall Double Eleven, promoción de productos del Día de San Valentín, varios productos tienen diferentes actividades de promoción

  • Reducción total: total 200 menos 50
  • Cada deducción completa: cada 100 completo menos 10
  • Descuento: 20% de descuento para dos artículos, 30% de descuento para tres artículos
  • Cantidad menos: tres piezas completas menos el precio más bajo

Suponiendo que un cliente compra dos prendas, primero las descuenta en un 20% y luego en un 50% cuando llegan a 200 y se multiplican las actividades promocionales ¿Cómo podemos calcular de forma flexible el importe del pedido?

Ejemplo de código

Interfaz de algoritmo de promoción para calcular el monto del pedido:

public interface PromotionAlgorithm {
    
    
    Order promotionAlgorithm(Order order);
}

Clase de implementación PromotionAlgorithm1, PromotionAlgorithm2:

public class PromotionAlgorithm1 implements PromotionAlgorithm {
    
    
    @Override
    public Order promotionAlgorithm(Order order) {
    
    
        System.out.println("打8折");
        order.setPrice(order.getPrice() * 0.8);
        return order;
    }
}
public class PromotionAlgorithm2 implements PromotionAlgorithm {
    
    
    @Override
    public Order promotionAlgorithm(Order order) {
    
    
        System.out.println("满200减了50");
        order.setPrice(order.getPrice() - 50);
        return order;
    }
}

Clase OrderService:

public class OrderService {
    
    
    public Order getOrderPrices(Order order, String... promotion) {
    
    
        for (String s : promotion) {
    
    
            if (s.equals("promotion-1")) {
    
    
                new PromotionAlgorithm1().promotionAlgorithm(order);
            } else if (s.equals("promotion-2")) {
    
    
                new PromotionAlgorithm2().promotionAlgorithm(order);
            }
        }
        return order;
    }
}

Categoría de prueba:

public class Test {
    
    

    public static void main(String[] args) {
    
    
        OrderService service = new OrderService();
        Order order = new Order();
        order.setPrice(1000.0);
        String[] array = {
    
    "promotion-1", "promotion-2"};
        Order result = service.getOrderPrices(order, array);
        System.out.println("最终我花了:" + result.getPrice());
    }
}

Inserte la descripción de la imagen aquí
Ahora piénselo, cuando necesite mejorar varios métodos de una clase, cuando el usuario utilizará el método mejorado a voluntad, ¿sigue siendo flexible el ciclo for anterior?

Mejora el código

Defina una interfaz OrderComponent:

public interface OrderComponent {
    
    

    /** 促销方式 */
    String getPromotion();

    /** 价格 */
    Double getPrice();
}

OrderConcreteComponent class: la clase que debe calcularse

public class OrderConcreteComponent implements OrderComponent {
    
    

    @Override
    public String getPromotion() {
    
    
        return "我买了三件衣服,衣服总共1000元,";
    }

    @Override
    public Double getPrice() {
    
    
        return 1000.0;
    }
}

Clase OrderDecorator: hay un atributo, que es la interfaz anterior OrderComponent, que implementa la interfaz OrderComponent

public class OrderDecorator implements OrderComponent {
    
    

    public OrderComponent component;

    public OrderDecorator(OrderComponent component) {
    
    
        this.component = component;
    }


    @Override
    public String getPromotion() {
    
    
        return this.component.getPromotion();
    }

    @Override
    public Double getPrice() {
    
    
        return this.component.getPrice();
    }
}

OrderDecoratorA class: clase de descuento

public class OrderDecoratorA extends OrderDecorator {
    
    

    public OrderDecoratorA(OrderComponent component) {
    
    
        super(component);
    }

    @Override
    public String getPromotion() {
    
    
        return this.component.getPromotion() + "衣服打了8折,";
    }

    @Override
    public Double getPrice() {
    
    
        return this.component.getPrice() * 0.8;
    }
}

OrderDecoratorB class: clase de reducción completa

public class OrderDecoratorB extends OrderDecorator {
    
    

    public OrderDecoratorB(OrderComponent component) {
    
    
        super(component);
    }

    @Override
    public String getPromotion() {
    
    
        return this.component.getPromotion() + "又满200减了50。";
    }

    @Override
    public Double getPrice() {
    
    
        return this.component.getPrice() - 50;
    }
}

Categoría de prueba:

public class Test {
    
    

    public static void main(String[] args) {
    
    
        OrderComponent component = new OrderConcreteComponent();
        OrderComponent c = new OrderDecorator(component);
        OrderComponent d = new OrderDecoratorA(c);
        OrderComponent e = new OrderDecoratorB(d);
        System.out.println(e.getPromotion());
        System.out.println("最终我花了:" + e.getPrice());
    }
}

Inserte la descripción de la imagen aquí
El código mejorado anterior es el uso básico del patrón decorador

Patrón de decorador

definición

De forma decorativa, atribuya responsabilidades dinámicamente al objeto sin cambiar su estructura.

intención

Agregue algunas responsabilidades adicionales a un objeto de forma dinámica. En términos de agregar funciones, el modo decorador es más flexible que generar subclases

Principalmente resuelve el problema

Generalmente, para extender una clase, usamos la herencia para lograrlo, porque la herencia introduce características estáticas a la clase, y con el aumento de funciones de extensión, la subclase estará muy hinchada.

Cuándo usar

Extienda la clase sin agregar muchas subclases

Pros y contras

ventaja:

  1. No cambie el código de clase específico, superponga dinámicamente la función de comportamiento mejorado
  2. Para ampliar la funcionalidad, los decoradores ofrecen una alternativa más flexible que la herencia.
  3. La clase de decoración y la clase de decoración se pueden desarrollar de forma independiente y no se combinarán entre sí.

Desventajas:

  1. La decoración multicapa es más complicada

Diagrama de clases:
Inserte la descripción de la imagen aquí
los roles involucrados:

  1. Rol de construcción abstracta (componente): proporciona una interfaz abstracta para estandarizar el objeto que está listo para recibir responsabilidades adicionales
  2. Rol del componente concreto (ConcreteComponent): Defina una clase que recibirá responsabilidades adicionales, es decir, la persona condecorada
  3. Rol de decorador: contiene una instancia de un objeto Componente y define una interfaz coherente con la interfaz abstracta
  4. Rol de decoración de hormigón (ConcreteDecorator): es decir, DecoratorA y DecoratorB en la figura anterior, responsables de asignar responsabilidades adicionales al objeto construido, es decir, el comportamiento de mejora de la función específica está en este rol

Clase de componente:

public interface Component {
    
    
    void sampleOperation();
}

Clase ConcreteComponent:

public class ConcreteComponent implements Component {
    
    
    @Override
    public void sampleOperation() {
    
    
        //do something
    }
}

Clase de decorador:

public class Decorator implements Component {
    
    

    private Component component;

    public Decorator(Component component) {
    
    
        this.component = component;
    }

    @Override
    public void sampleOperation() {
    
    
        this.component.sampleOperation();
    }
}

Clase ConcreteDecorator:

public class ConcreteDecorator extends Decorator {
    
    

    public ConcreteDecorator(Component component) {
    
    
        super(component);
    }

    @Override
    public void sampleOperation() {
    
    
        super.sampleOperation();
    }
}

El patrón de decorador a menudo se llama patrón de envoltura, porque cada clase de decoración de concreto envuelve la siguiente clase de decoración de concreto o clase de construcción de concreto.
Supongamos que hay dos clases de decoración de concreto Decorator1, Decorator2 y una clase de construcción de concreto ConcreteComponent:
Inserte la descripción de la imagen aquí
Sí, es correcto, solo como una matrioska, envuelta en una capa

Los setenta y dos cambios del rey mono

Todo el mundo sabe que Monkey King tiene setenta y dos cambios, y cada cambio le traerá una habilidad adicional, convirtiéndose en un pez que puede nadar en el agua y un pájaro que puede volar en el aire, pero no importa cuál sea el cambio, Erlang en los ojos, o las
Inserte la descripción de la imagen aquí
categorías de un mono mono: cambios similares tienen setenta y dos

public interface MonkeyKing {
    
    
    /** 七十二变 */
    String change();
}

Gran clase de la deidad santa:

public class ConcreteMonkey implements MonkeyKing {
    
    
    @Override
    public String change() {
    
    
        return "我是齐天大圣本尊!";
    }
}

Encarnación del Gran Sabio:

public class DecoratorMonkeyChange implements MonkeyKing {
    
    

    public MonkeyKing king;

    public DecoratorMonkeyChange(MonkeyKing king) {
    
    
        this.king = king;
    }

    @Override
    public String change() {
    
    
        return this.king.change();
    }
}

El Avatar del Gran Sabio:

public class DecoratorMonkeyChange1 extends DecoratorMonkeyChange {
    
    

    public DecoratorMonkeyChange1(MonkeyKing king) {
    
    
        super(king);
    }
    
    @Override
    public String change() {
    
    
        return this.king.change() + "变成了鱼!";
    }
}
public class DecoratorMonkeyChange2 extends DecoratorMonkeyChange {
    
    

    public DecoratorMonkeyChange2(MonkeyKing king) {
    
    
        super(king);
    }

    @Override
    public String change() {
    
    
        return this.king.change() + "变成了鸟!";
    }
}

Categoría de prueba:

public class TestMonkey {
    
    
    public static void main(String[] args) {
    
    
        MonkeyKing king = new ConcreteMonkey();
        MonkeyKing a = new DecoratorMonkeyChange(king);
        MonkeyKing b = new DecoratorMonkeyChange1(a);
        MonkeyKing c = new DecoratorMonkeyChange2(b);
        System.out.println(c.change());
    }
}

Inserte la descripción de la imagen aquí
Diagrama de clase:
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_34365173/article/details/108058418
Recomendado
Clasificación