12.7 实验二十四模板方法模式 实验二十五访问者模式

实验 24:模板方法模式
本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:
1、理解模板方法模式的动机,掌握该模式的结构;
2、能够利用模板方法模式解决实际问题。

[实验任务一]:数据库连接
对数据库的操作一般包括连接、打开、使用、关闭等步骤,在数据库操作模板类中我们定义了connDB()、openDB()、useDB()、closeDB()四个方法分别对应这四个步骤。对于不同类型的数据库(如SQL Server和Oracle),其操作步骤都一致,只是连接数据库connDB()方法不同,现使用模板方法模式对其进行设计。
实验要求:
1.画出对应的类图;
2.提交源代码;
3.注意编程规范。
image

1. DatabaseTemplate.java
public abstract class DatabaseTemplate {
    /**
     * 模板方法:定义数据库操作的固定步骤(连接→打开→使用→关闭)
     * 设为final防止子类重写流程,保证步骤一致性
     */
    public final void execute() {
        connDB();   // 步骤1:连接数据库(子类实现)
        openDB();   // 步骤2:打开数据库(通用实现)
        useDB();    // 步骤3:使用数据库(通用实现)
        closeDB();  // 步骤4:关闭数据库(通用实现)
    }

    /**
     * 抽象方法:连接数据库(子类实现具体数据库的连接逻辑)
     */
    protected abstract void connDB();

    /**
     * 具体方法:打开数据库(通用逻辑)
     */
    protected void openDB() {
        System.out.println("通用操作:打开数据库连接,初始化会话参数");
    }

    /**
     * 具体方法:使用数据库(通用逻辑)
     */
    protected void useDB() {
        System.out.println("通用操作:执行SQL语句,处理数据查询/更新");
    }

    /**
     * 具体方法:关闭数据库(通用逻辑)
     */
    protected void closeDB() {
        System.out.println("通用操作:关闭数据库连接,释放资源\n");
    }}
2. SQLServerDB.java
public class SQLServerDB extends DatabaseTemplate {
    @Override
    protected void connDB() {
        System.out.println("SQL Server特有操作:通过JDBC连接SQL Server,URL格式为jdbc:sqlserver://<主机>:<端口>;databaseName=<库名>");
    }}
3. OracleDB.java
public class OracleDB extends DatabaseTemplate {
    @Override
    protected void connDB() {
        System.out.println("Oracle特有操作:通过JDBC连接Oracle,URL格式为jdbc:oracle:thin:@<主机>:<端口>:<SID>");
    }}
4. DatabaseTemplateTest.java
public class DatabaseTemplateTest {
    public static void main(String[] args) {
        // 1. 操作SQL Server数据库
        System.out.println("===== 执行SQL Server数据库操作 =====");
        DatabaseTemplate sqlServer = new SQLServerDB();
        sqlServer.execute();

        // 2. 操作Oracle数据库
        System.out.println("===== 执行Oracle数据库操作 =====");
        DatabaseTemplate oracle = new OracleDB();
        oracle.execute();
    }}

实验 25:访问者模式
本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:
1、理解访问者模式的动机,掌握该模式的结构;
2、能够利用访问者模式法解决实际问题。

[实验任务一]:打包员
在我们课堂上的“购物车”的例子中,增加一个新的访问者:打包员,负责对购物车中货物装包。
实验要求:
1.画出对应的类图;
2.提交源代码;
3. 注意编程规范。
image

1. ProductElement.java
public interface ProductElement {
    /**
     * 接受访问者访问的方法
     * @param visitor 访问者对象
     */
    void accept(Visitor visitor);}
2. Book.java
public class Book implements ProductElement {
    // 商品名称
    private final String name;
    // 商品价格
    private final double price;
    // 书籍重量(kg)
    private final double weight;

    /**
     * 构造方法:初始化书籍属性
     * @param name 书籍名称
     * @param price 书籍价格
     * @param weight 书籍重量(kg)
     */
    public Book(String name, double price, double weight) {
        this.name = name;
        this.price = price;
        this.weight = weight;
    }

    // Getter方法
    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public double getWeight() {
        return weight;
    }

    @Override
    public void accept(Visitor visitor) {
        // 调用访问者的书籍访问方法,完成双重分派的第二重绑定
        visitor.visit(this);
    }}
3. ElectronicProduct.java
public class ElectronicProduct implements ProductElement {
    // 商品名称
    private final String name;
    // 商品价格
    private final double price;
    // 电子产品尺寸(小/中/大)
    private final String size;

    /**
     * 构造方法:初始化电子产品属性
     * @param name 电子产品名称
     * @param price 电子产品价格
     * @param size 电子产品尺寸(小/中/大)
     */
    public ElectronicProduct(String name, double price, String size) {
        this.name = name;
        this.price = price;
        this.size = size;
    }

    // Getter方法
    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }

    public String getSize() {
        return size;
    }

    @Override
    public void accept(Visitor visitor) {
        // 调用访问者的电子产品访问方法,完成双重分派的第二重绑定
        visitor.visit(this);
    }}
4. Visitor.java
public interface Visitor {
    /**
     * 访问书籍元素的方法
     * @param book 书籍对象
     */
    void visit(Book book);

    /**
     * 访问电子产品元素的方法
     * @param eProduct 电子产品对象
     */
    void visit(ElectronicProduct eProduct);}
5. PriceVisitor.java
public class PriceVisitor implements Visitor {
    // 购物车商品总价
    private double totalPrice = 0.0;

    /**
     * 获取计算后的商品总价
     * @return 总价(元)
     */
    public double getTotalPrice() {
        return totalPrice;
    }

    @Override
    public void visit(Book book) {
        // 累加书籍价格
        totalPrice += book.getPrice();
        System.out.println("统计书籍《" + book.getName() + "》价格:" + book.getPrice() + "元");
    }

    @Override
    public void visit(ElectronicProduct eProduct) {
        // 累加电子产品价格
        totalPrice += eProduct.getPrice();
        System.out.println("统计电子产品《" + eProduct.getName() + "》价格:" + eProduct.getPrice() + "元");
    }}
6. PackagerVisitor.java
public class PackagerVisitor implements Visitor {
    // 打包详情字符串(拼接所有商品的打包信息)
    private String packageDetail = "【购物车商品打包详情】\n";

    /**
     * 获取生成的打包详情
     * @return 打包详情描述
     */
    public String getPackageDetail() {
        return packageDetail;
    }

    @Override
    public void visit(Book book) {
        // 书籍打包规则:重量≤0.5kg用薄纸盒,>0.5kg用厚纸盒+防震膜
        String packageRule;
        if (book.getWeight() <= 0.5) {
            packageRule = "薄纸盒包装(轻便型)";
        } else {
            packageRule = "厚纸盒+防震膜包装(防压型)";
        }
        packageDetail += "书籍《" + book.getName() + "》- 重量:" + book.getWeight() + "kg → " + packageRule + "\n";
    }

    @Override
    public void visit(ElectronicProduct eProduct) {
        // 电子产品打包规则:按尺寸选择包装类型
        String packageRule;
        switch (eProduct.getSize()) {
            case "小":
                packageRule = "气泡袋+小纸盒包装(便携型)";
                break;
            case "中":
                packageRule = "泡沫垫+中纸箱包装(防护型)";
                break;
            case "大":
                packageRule = "定制泡沫+大纸箱+木架包装(加固型)";
                break;
            default:
                packageRule = "通用防震包装(默认型)";
        }
        packageDetail += "电子产品《" + eProduct.getName() + "》- 尺寸:" + eProduct.getSize() + " → " + packageRule + "\n";
    }}
7. ShoppingCart.java
/public class ShoppingCart {
    // 商品元素列表(存储购物车中的所有商品)
    private final List<ProductElement> products = new ArrayList<>();

    /**
     * 向购物车添加商品的方法
     * @param product 商品元素对象
     */
    public void addProduct(ProductElement product) {
        products.add(product);
    }

    /**
     * 接受访问者访问的方法,遍历所有商品并调用其accept方法
     * @param visitor 访问者对象
     */
    public void accept(Visitor visitor) {
        for (ProductElement product : products) {
            product.accept(visitor);
        }
    }}
8. ShoppingCartVisitorTest.java
public class ShoppingCartVisitorTest {
    public static void main(String[] args) {
        // 1. 创建购物车并添加商品
        ShoppingCart cart = new ShoppingCart();
        cart.addProduct(new Book("Java编程思想", 108.0, 0.8));
        cart.addProduct(new ElectronicProduct("无线蓝牙耳机", 299.0, "小"));
        cart.addProduct(new ElectronicProduct("15.6英寸笔记本电脑", 5999.0, "大"));

        // 2. 价格统计访问者处理购物车
        System.out.println("===== 购物车商品价格统计 =====");
        PriceVisitor priceVisitor = new PriceVisitor();
        cart.accept(priceVisitor);
        System.out.println("购物车商品总价:" + priceVisitor.getTotalPrice() + "元\n");

        // 3. 打包员访问者处理购物车
        System.out.println("===== 购物车商品打包详情 =====");
        PackagerVisitor packagerVisitor = new PackagerVisitor();
        cart.accept(packagerVisitor);
        System.out.println(packagerVisitor.getPackageDetail());
    }}
posted @ 2026-01-03 13:34  liu某人  阅读(1)  评论(0)    收藏  举报