12.3 实验二十一观察者模式 实验二十二状态模式 实验二十三策略模式
实验 21:观察者模式
本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:
1、理解观察者模式的动机,掌握该模式的结构;
2、能够利用观察者模式解决实际问题。
[实验任务一]:股票提醒
当股票的价格上涨或下降5%时,会通知持有该股票的股民,当股民听到价格上涨的消息时会买股票,当价格下降时会大哭一场。
实验要求:
1.画出对应类图;
2.提交源代码;
3.注意编程规范。

StockSubject.java
import java.util.ArrayList;import java.util.List;
public abstract class StockSubject {
// 维护观察者(股民)列表
protected List<Investor> observers = new ArrayList<>();
/**
* 注册观察者(股民订阅股票)
* @param investor 要注册的股民
*/
public void registerObserver(Investor investor) {
observers.add(investor);
}
/**
* 移除观察者(股民取消订阅)
* @param investor 要移除的股民
*/
public void removeObserver(Investor investor) {
observers.remove(investor);
}
/**
* 通知所有观察者(股票价格变化触发)
*/
public abstract void notifyObservers();}
2.ConcreteStock.java
public class ConcreteStock extends StockSubject {
// 股票名称
private final String stockName;
// 当前价格
private double price;
// 上一次价格(用于计算变化率)
private double lastPrice;
/**
* 构造方法:初始化股票名称和初始价格
* @param stockName 股票名称
* @param price 初始价格
*/
public ConcreteStock(String stockName, double price) {
this.stockName = stockName;
this.price = price;
this.lastPrice = price; // 初始时上一次价格=当前价格
}
/**
* 设置股票价格,触发变化率检查和通知
* @param newPrice 新价格
*/
public void setPrice(double newPrice) {
this.lastPrice = this.price; // 保存上一次价格
this.price = newPrice;
// 价格变化率≥5%时通知观察者
if (Math.abs(getPriceChangeRate()) >= 5) {
notifyObservers();
}
}
/**
* 计算价格变化率(百分比)
* @return 变化率(正数=涨,负数=跌)
*/
public double getPriceChangeRate() {
return ((price - lastPrice) / lastPrice) * 100;
}
/**
* 获取股票名称
* @return 股票名称
*/
public String getStockName() {
return stockName;
}
/**
* 获取当前价格
* @return 当前价格
*/
public double getPrice() {
return price;
}
@Override
public void notifyObservers() {
boolean isRise = getPriceChangeRate() > 0; // 是否上涨
for (Investor investor : observers) {
investor.update(this, isRise); // 通知每个股民
}
}}
3. Investor.java
public interface Investor {
/**
* 接收股票价格变化通知
* @param stock 变化的股票
* @param isRise 股票是否上涨
*/
void update(ConcreteStock stock, boolean isRise);}
4.ConcreteInvestor.java
public class ConcreteInvestor implements Investor {
// 股民姓名
private final String name;
/**
* 构造方法:初始化股民姓名
* @param name 股民姓名
*/
public ConcreteInvestor(String name) {
this.name = name;
}
@Override
public void update(ConcreteStock stock, boolean isRise) {
double changeRate = stock.getPriceChangeRate();
System.out.println("===== " + stock.getStockName() + "价格变化通知 =====");
System.out.println("股民" + name + "收到消息:" +
(isRise ? "上涨" + String.format("%.2f", changeRate) + "%" :
"下跌" + String.format("%.2f", Math.abs(changeRate)) + "%"));
// 根据涨跌执行动作
if (isRise) {
System.out.println("股民" + name + ":赶紧加仓买!");
} else {
System.out.println("股民" + name + ":呜呜呜,亏麻了!");
}
System.out.println("当前股价:" + stock.getPrice() + "元\n");
}}
4.StockObserverTest.java
public class StockObserverTest {
public static void main(String[] args) {
// 1. 创建具体股票(茅台,初始价格1800元)
ConcreteStock maotaiStock = new ConcreteStock("贵州茅台", 1800.0);
// 2. 创建股民(观察者)
Investor zhangsan = new ConcreteInvestor("张三");
Investor lisi = new ConcreteInvestor("李四");
Investor wangwu = new ConcreteInvestor("王五");
// 3. 股民订阅股票
maotaiStock.registerObserver(zhangsan);
maotaiStock.registerObserver(lisi);
maotaiStock.registerObserver(wangwu);
// 4. 模拟股票价格变化(上涨5%:1800→1890)
System.out.println("【场景1:股票上涨5%】");
maotaiStock.setPrice(1890.0);
// 5. 模拟股票价格下跌6%(1890→1776.6)
System.out.println("【场景2:股票下跌6%】");
maotaiStock.setPrice(1776.6);
// 6. 移除李四后,股票再上涨(1776.6→1865.43,上涨5%)
System.out.println("【场景3:移除李四后,股票再上涨5%】");
maotaiStock.removeObserver(lisi);
maotaiStock.setPrice(1865.43);
}}
实验 22:状态模式
本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:
1、理解状态模式的动机,掌握该模式的结构;
2、能够利用状态模式解决实际问题。
[实验任务一]:银行账户
用Java代码模拟实现课堂上的“银行账户”的实例,要求编写客户端测试代码模拟用户存款和取款,注意账户对象状态和行为的变化。
实验要求:
1.画出对应的类图;
2.提交源代码;
3. 注意编程规范。

1. AccountState.java
public abstract class AccountState {
protected Account account;
/**
* 构造方法:关联账户上下文
* @param account 所属账户
*/
public AccountState(Account account) {
this.account = account;
}
/**
* 存款行为(子类实现)
* @param amount 存款金额
*/
public abstract void deposit(double amount);
/**
* 取款行为(子类实现)
* @param amount 取款金额
*/
public abstract void withdraw(double amount);}
2. NormalState.java
public class NormalState extends AccountState {
/**
* 构造方法:初始化正常状态
* @param account 所属账户
*/
public NormalState(Account account) {
super(account);
}
/**
* 构造方法:带初始余额的正常状态
* @param account 所属账户
* @param balance 初始余额
*/
public NormalState(Account account, double balance) {
super(account);
this.account.setBalance(balance);
}
@Override
public void deposit(double amount) {
// 正常状态存款:直接增加余额
double newBalance = account.getBalance() + amount;
account.setBalance(newBalance);
System.out.println("账户【" + account.getAccountName() + "】存款" + amount + "元,当前余额:" + newBalance + "元(状态:正常)");
}
@Override
public void withdraw(double amount) {
double currentBalance = account.getBalance();
if (amount <= currentBalance) {
// 取款≤余额:正常取款
double newBalance = currentBalance - amount;
account.setBalance(newBalance);
System.out.println("账户【" + account.getAccountName() + "】取款" + amount + "元,当前余额:" + newBalance + "元(状态:正常)");
} else {
// 取款>余额:切换为透支状态
double newBalance = currentBalance - amount;
account.setBalance(newBalance);
account.setState(new OverdraftState(account, newBalance));
System.out.println("账户【" + account.getAccountName() + "】取款" + amount + "元,当前余额:" + newBalance + "元(状态:透支)");
}
}}
3. OverdraftState.java
public class OverdraftState extends AccountState {
// 透支额度(固定为1000元)
private static final double OVERDRAFT_LIMIT = 1000;
/**
* 构造方法:初始化透支状态
* @param account 所属账户
*/
public OverdraftState(Account account) {
super(account);
}
/**
* 构造方法:带初始余额的透支状态
* @param account 所属账户
* @param balance 初始余额
*/
public OverdraftState(Account account, double balance) {
super(account);
this.account.setBalance(balance);
}
@Override
public void deposit(double amount) {
double currentBalance = account.getBalance();
double newBalance = currentBalance + amount;
account.setBalance(newBalance);
if (newBalance >= 0) {
// 存款后余额≥0:切换为正常状态
account.setState(new NormalState(account, newBalance));
System.out.println("账户【" + account.getAccountName() + "】存款" + amount + "元,当前余额:" + newBalance + "元(状态:恢复正常)");
} else {
// 存款后仍透支:保持透支状态
System.out.println("账户【" + account.getAccountName() + "】存款" + amount + "元,当前余额:" + newBalance + "元(状态:透支)");
}
}
@Override
public void withdraw(double amount) {
double currentBalance = account.getBalance();
double overdraftAmount = Math.abs(currentBalance); // 当前透支金额
if (amount <= (OVERDRAFT_LIMIT - overdraftAmount)) {
// 取款≤剩余透支额度:允许透支取款
double newBalance = currentBalance - amount;
account.setBalance(newBalance);
System.out.println("账户【" + account.getAccountName() + "】透支取款" + amount + "元,当前余额:" + newBalance + "元(状态:透支)");
} else {
// 取款>剩余透支额度:拒绝取款
System.out.println("账户【" + account.getAccountName() + "】取款失败!剩余透支额度:" + (OVERDRAFT_LIMIT - overdraftAmount) + "元,请求取款:" + amount + "元");
}
}}
4. Account.java
public class Account {
// 账户姓名
private final String accountName;
// 账户余额
private double balance;
// 当前账户状态
private AccountState state;
/**
* 构造方法:初始化账户
* @param accountName 账户姓名
* @param initBalance 初始余额
*/
public Account(String accountName, double initBalance) {
this.accountName = accountName;
this.balance = initBalance;
// 初始状态:余额≥0为正常状态,否则为透支状态
if (initBalance >= 0) {
this.state = new NormalState(this, initBalance);
} else {
this.state = new OverdraftState(this, initBalance);
}
System.out.println("账户【" + accountName + "】创建成功,初始余额:" + initBalance + "元(初始状态:" + (initBalance >= 0 ? "正常" : "透支") + ")");
}
/**
* 存款操作(委托给当前状态)
* @param amount 存款金额
*/
public void deposit(double amount) {
if (amount <= 0) {
System.out.println("存款失败!金额必须大于0");
return;
}
state.deposit(amount);
}
/**
* 取款操作(委托给当前状态)
* @param amount 取款金额
*/
public void withdraw(double amount) {
if (amount <= 0) {
System.out.println("取款失败!金额必须大于0");
return;
}
state.withdraw(amount);
}
// Getter & Setter
public void setState(AccountState state) {
this.state = state;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public String getAccountName() {
return accountName;
}}
5. AccountStateTest.java
public class AccountStateTest {
public static void main(String[] args) {
// 1. 创建账户(初始余额2000元,正常状态)
Account account = new Account("张三", 2000);
// 2. 正常状态取款1500元
System.out.println("\n--- 操作1:正常取款1500元 ---");
account.withdraw(1500);
// 3. 正常状态取款1000元(导致透支)
System.out.println("\n--- 操作2:正常取款1000元(透支) ---");
account.withdraw(1000);
// 4. 透支状态存款800元(仍透支)
System.out.println("\n--- 操作3:透支存款800元 ---");
account.deposit(800);
// 5. 透支状态取款200元(在透支额度内)
System.out.println("\n--- 操作4:透支取款200元 ---");
account.withdraw(200);
// 6. 透支状态存款1500元(恢复正常)
System.out.println("\n--- 操作5:透支存款1500元(恢复正常) ---");
account.deposit(1500);
// 7. 正常状态取款3000元(再次透支)
System.out.println("\n--- 操作6:正常取款3000元(透支) ---");
account.withdraw(3000);
// 8. 透支状态取款1200元(超过透支额度)
System.out.println("\n--- 操作7:透支取款1200元(超限) ---");
account.withdraw(1200);
}}
实验 23:策略模式
本次实验属于模仿型实验,通过本次实验学生将掌握以下内容:
1、理解策略模式的动机,掌握该模式的结构;
2、能够利用策略模式解决实际问题。
[实验任务一]:旅行方式的选择
旅游的出行方式有乘坐飞机旅行、乘火车旅行和自行车游,不同的旅游方式有不同的实现过程,客户可以根据自己的需要选择一种合适的旅行方式。
实验要求:
1.画出对应的类图;
2.提交源代码;
3.注意编程规范。

1. TravelStrategy.java
public interface TravelStrategy {
/**
* 执行具体的旅行方式
*/
void travel();}
2. PlaneTravel.java
public class PlaneTravel implements TravelStrategy {
@Override
public void travel() {
System.out.println("选择飞机旅行:");
System.out.println("1. 预订机票(需身份证/护照)");
System.out.println("2. 提前2小时到机场办理值机");
System.out.println("3. 安检后登机,飞行时间短,适合长途旅行");
System.out.println("------------------------");
}}
3. TrainTravel.java
public class TrainTravel implements TravelStrategy {
@Override
public void travel() {
System.out.println("选择火车旅行:");
System.out.println("1. 购买火车票(需身份证)");
System.out.println("2. 提前30分钟到车站检票");
System.out.println("3. 乘坐高铁/普速列车,站点覆盖广,性价比高");
System.out.println("------------------------");
}}
4. BikeTravel.java
public class BikeTravel implements TravelStrategy {
@Override
public void travel() {
System.out.println("选择自行车旅行:");
System.out.println("1. 检查自行车车况(轮胎、刹车等)");
System.out.println("2. 准备骑行装备(头盔、水壶)");
System.out.println("3. 沿途欣赏风景,适合短途休闲旅行");
System.out.println("------------------------");
}}
5. TravelContext.java
public class TravelContext {
// 当前使用的旅行策略
private TravelStrategy strategy;
/**
* 构造方法:初始化策略
* @param strategy 旅行策略
*/
public TravelContext(TravelStrategy strategy) {
this.strategy = strategy;
}
/**
* 切换旅行策略
* @param strategy 新的旅行策略
*/
public void setStrategy(TravelStrategy strategy) {
this.strategy = strategy;
}
/**
* 执行当前策略的旅行行为
*/
public void executeTravel() {
strategy.travel();
}}
6. TravelStrategyTest.java
public class TravelStrategyTest {
public static void main(String[] args) {
// 1. 选择飞机旅行
System.out.println("===== 第一次旅行选择 =====");
TravelContext context = new TravelContext(new PlaneTravel());
context.executeTravel();
// 2. 切换为火车旅行
System.out.println("===== 第二次旅行选择 =====");
context.setStrategy(new TrainTravel());
context.executeTravel();
// 3. 切换为自行 车旅行
System.out.println("===== 第三次旅行选择 =====");
context.setStrategy(new BikeTravel());
context.executeTravel();
}}

浙公网安备 33010602011771号