注册

访问者模式:多品类商品打折场景

0.基础


0.0解决的痛点


它可以在不修改原有类的情况下,扩展新的操作,而策略模式则需要改变上下文类来引入新的策略。



  • 扩展性更强

    • 访问者模式使得你可以在不修改现有类的情况下添加新的操作。假设你有多个对象构成的复杂结构,并且要在这些对象上执行不同的操作。
    • 使用访问者模式,你可以为每个对象定义一个访问者,而每次需要添加新的操作时,只需要增加一个新的访问者类。这样,原有类不会被修改,符合开闭原则(对扩展开放,对修改关闭)。
    • 相反,策略模式更多是通过替换算法来改变行为。如果你的业务逻辑复杂,需要在同一个对象中实现多个策略,频繁地改变策略可能会导致对象内部逻辑变得非常复杂,增加维护成本。


  • 职责单一,逻辑分离

    • 访问者模式将行为与对象结构分离,访问者本身只关心如何对不同对象执行操作,而不需要关心对象的具体实现。这种方式将操作逻辑与数据结构解耦,符合单一职责原则。
    • 策略模式中,每种策略会嵌入到目标对象中,这会使得目标对象承担过多的责任,尤其是在需要处理大量策略的情况下,会导致对象变得非常臃肿。


  • 操作集中统一管理

    • 使用访问者模式时,所有的操作都集中在访问者类中进行管理。
    • 假设有多个元素需要执行不同的操作,访问者模式将这些操作集中到访问者中,避免了分散在各个策略中的问题,便于管理和维护。
    • 策略模式则往往需要将每个策略分散在不同的策略类中,随着策略增多,管理和维护会变得越来越困难,尤其是当策略之间有依赖或交互时,复杂性会迅速增加。


  • 适合复杂结构对象的处理

    • 访问者模式特别适合在对象结构复杂且需要遍历的场景中使用。
    • 例如,树形结构或对象图的遍历,这时每个节点的处理逻辑可以独立出来,并通过访问者来实现。
    • 访问者可以对这些节点类型的元素进行访问和操作,无需修改元素类本身。
    • 策略模式一般用于动态地改变同一对象的行为,不适合处理复杂的对象结构,特别是当需要在多个元素中进行遍历和操作时,策略模式会显得不够灵活。


  • 总结:

    • 访问者模式更适合在你需要对复杂结构的对象执行多个操作,并且希望操作与对象本身分离的场景。
    • 它更方便扩展,避免了复杂的继承结构或不断修改已有类。
    • 而策略模式则适合于在单一对象上动态替换行为,但对于复杂对象结构的处理往往会导致逻辑分散,扩展性差。



0.1代码结构图


访问者模式-商品打折场景-代码结构图.drawio.png


0.2业务流程图


访问者模式业务流程图.png


0.3请求Json


localhost:8080/VisitorPattern/calculateDiscount
   POST类型
  ["electronics", "clothing", "food"]


1.代码结构


1.1Pojo


package com.xiaoyongcai.io.designmode.pojo.VisitorPattern;

public interface Product {
   void accept(ProductVisitor visitor);
}


package com.xiaoyongcai.io.designmode.pojo.VisitorPattern;

import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Clothing;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Electronics;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Food;

public interface ProductVisitor {
   void visit(Electronics electronics);
   void visit(Clothing clothing);
   void visit(Food food);
}


package com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl;

import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.Product;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductVisitor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Clothing implements Product {
   private double price;
   @Override
   public void accept(ProductVisitor visitor) {
       visitor.visit(this);  // 传递给访问者
  }
}


package com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl;

import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.Product;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductVisitor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Electronics implements Product {
   private double price;
   @Override
   public void accept(ProductVisitor visitor) {
       visitor.visit(this);  // 传递给访问者
  }
}


package com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl;

import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.Product;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductVisitor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Food implements Product {
   private double price;
   @Override
   public void accept(ProductVisitor visitor) {
       visitor.visit(this);  // 传递给访问者
  }
}


package com.xiaoyongcai.io.designmode.pojo.VisitorPattern.VisitorImpl;

import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Clothing;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Electronics;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Food;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductVisitor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Slf4j
public class DiscountVisitor implements ProductVisitor {
   private double totalDiscount = 0;
   @Override
   public void visit(Electronics electronics) {
       //电子产品打八折
       totalDiscount += electronics.getPrice()*0.2;
       log.info("[访问者模式]:电子产品打8折后价格为"+electronics.getPrice()*0.2+"原价为"+electronics.getPrice());

  }

   @Override
   public void visit(Clothing clothing) {
       //衣物商品打7折
       totalDiscount+=clothing.getPrice()*0.3;
       log.info("[访问者模式]衣物商品打7折后价格为"+clothing.getPrice()*0.2+"原价为"+clothing.getPrice());
  }

   @Override
   public void visit(Food food) {
       //食品商品打9折
       totalDiscount += food.getPrice()*0.1;
       log.info("[访问者模式]食品商品打9折后价格为"+food.getPrice()*0.2+"原价为"+food.getPrice());
  }
}


1.2Service


package com.xiaoyongcai.io.designmode.Service.VisitorPattern;

import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.Product;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.VisitorImpl.DiscountVisitor;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductService {

   public double calculateTotalDiscount(List<Product> products) {
       // 创建一个DiscountVisitor实例
       DiscountVisitor discountVisitor = new DiscountVisitor();

       // 遍历每个商品,执行折扣计算
       for (Product product : products) {
           product.accept(discountVisitor);
      }

       // 返回总折扣
       return discountVisitor.getTotalDiscount();
  }
}


1.3Controller


package com.xiaoyongcai.io.designmode.Controller.VisitorPattern;

import com.xiaoyongcai.io.designmode.Service.VisitorPattern.ProductService;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.Product;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Clothing;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Electronics;
import com.xiaoyongcai.io.designmode.pojo.VisitorPattern.ProductImpl.Food;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("VisitorPattern")
public class ProductController {

   @Autowired
   private ProductService productService;

   @PostMapping("/calculateDiscount")
   public String calculateDiscount(@RequestBody List<String> productTypes) {
       List<Product> products = new ArrayList<>();

       // 根据传入的商品类型,创建不同的商品实例
       for (String type : productTypes) {
           switch (type) {
               case "electronics":
                   products.add(new Electronics(100));  // 假设价格是100
                   break;
               case "clothing":
                   products.add(new Clothing(150));    // 假设价格是150
                   break;
               case "food":
                   products.add(new Food(50));         // 假设价格是50
                   break;
          }
      }
       productService.calculateTotalDiscount(products);
       // 调用Service层计算折扣
       return "请在控制台检查访问者模式是否工作";
  }
}


作者:Asthenia0412
来源:juejin.cn/post/7440842636228919348

0 个评论

要回复文章请先登录注册