运用设计模式设计一个票务系统(策略模式使用)

策略模式在票务系统的使用

为什么要选用策略模式

票务系统为用户分等级,普通用户,白银用户,黄金用户; 每种不同的用户都有不同的折扣策略。

同时,为了系统的开放性,我们设计的项目是可以添加新的用户级别同时不修改源代码。


(资料图片仅供参考)

这些就恰恰是策略模式能解决的问题,这就是为什么我要选它。

不懂策略模式的小伙伴可以看我的介绍: 【设计模式】行为型模式其九: 策略模式 - 掘金 (juejin.cn)

项目中书写

策略抽象类

// 定义打折方法

public interface Discount {    BigDecimal discount(BigDecimal price);}复制代码

具体策略类

// 普通用户采取不打折策略

public class NormalDiscount implements Discount{    private final double discount;    public NormalDiscount(){        this.discount = 1.0;    }    @Override    public BigDecimal discount(BigDecimal price) {        return price.multiply(new BigDecimal(discount));    }}复制代码

// 白银用户采取打八折的方式

public class SilverDiscount implements Discount{    private final double discount;    public SilverDiscount(){        this.discount = 0.8;    }    @Override    public BigDecimal discount(BigDecimal price) {        return price.multiply(new BigDecimal(discount));    }}复制代码

// 黄金用户采取打六折的方式

public class GoldDiscount implements Discount{    private final double discount;    public GoldDiscount(){        this.discount = 0.6;    }    @Override    public BigDecimal discount(BigDecimal price) {        return price.multiply(new BigDecimal(discount));    }}复制代码

具体环境类

将打折功能放在一个对象内,公开一个获得价格接口,便于调用和统一处理

public class Price {    private BigDecimal price;    private Discount discount;    public void setPrice(BigDecimal price){        this.price = price;    }    public void setDiscount(Discount discount){        this.discount = discount;    }    public BigDecimal getPrice(){        return discount.discount(this.price);    }}复制代码

XML 文件

com.example.ticket.service.stratege.SilverDiscount复制代码

XMl文件读取类

public class DiscountXmlUtil {    public static Object getBean(){        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();        try {            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();            Document doc = documentBuilder.parse(\"D:\gitee	icket	icket-management-system	icket\src\main\" +                    \"\resources\" +                    \"\discount.xml\");            NodeList className = doc.getElementsByTagName(\"className\");            Node firstChild = className.item(0).getFirstChild();            String nodeValue = firstChild.getNodeValue();            ClassaClass = Class.forName(nodeValue);            Constructorconstructor = aClass.getConstructor();            return Class.forName(nodeValue).getConstructor().newInstance();        } catch (ParserConfigurationException | IOException | SAXException | ClassNotFoundException |                 InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {            throw new RuntimeException(e);        }    }}复制代码

具体调用类

我们这算是一个系统,所以我们何时会去使用价格打折机制呢?

没错,就是生成订单的时候,所以我们调用方法写在service层里。

那我们肯定是要根据前端传来的用户信息,读取用户类的身份字段,并为其选择合适的打折策略。

@Overridepublic SysOrder getOrder() {    // 获得价格对象    Price price = new Price();    // 设置商品价格    price.setPrice(new BigDecimal(\"10.00\"));    // 设置打折策略, 根据XML文件来设置    price.setDiscount((Discount) DiscountXmlUtil.getBean());    // 通过统一接口来获得价格    BigDecimal price1 = price.getPrice();    // 之后就是对Order对象的封装, 省略。。。。。。    System.out.println(price1);    return null;}复制代码

一些细节提示

具体类里的discount字段属于赋值一次,永远不变的,所以加上final字段。 当你想要添加其它打折策略, 可以直接继承Discount,然后改写方法即可 当你还要进行一些特殊操作,比如添加积分,可以在具体打折类进行操作。当然,我更建议在Price对象里进行操作,毕竟这算是一种公共操作,可以在Price里统一进行。 根据XML文件来动态生成策略类,这样虽然不会修改源代码,但是需要根据用户身份来修改XML文件,所以我们还得在DiscountXMLUtil类中书写修改XML文件的方法。

原文链接:https://juejin.cn/post/7226013112406294589