java设计模式之行为型模式(11种)
行为型模式
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
行为型模式分为类行为模式和对象型模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或者聚合关系比继承关系耦合度低,满足合成复用原则,所以对象行为模式比类行为模式具有更大的灵活性。
分为:模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式。(除了模板方法模式和解释器模式是类行为型模式,其他的全部属于对象行为型模式。)
模板方法模式
抽象类:定义模板方法和抽象方法。为防止恶意操作,一般模板方法都加上 final 关键词。
public abstract class AbstractClass {// 模板方法定义public final void cookProcess() {pourOil();heatOil();pourVegetable();pourSauce();fry();}// 第一步:倒油是一样的,直接实现public void pourOil() {System.out.println("倒油");}// 第二步:热油是一样的,直接实现public void heatOil() {System.out.println("热油");}// 第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心),抽象方法public abstract void pourVegetable();// 第四步:倒调味料是不一样,抽象方法public abstract void pourSauce();// 第五步:翻炒是一样的,直接实现public void fry() {System.out.println("炒啊炒啊炒到熟啊");}
}
具体子类:实现模板方法中的抽象方法和钩子方法
/*** 炒包菜类*/
public class ConcreteClass_BaoCai extends AbstractClass {public void pourVegetable() {System.out.println("下锅的蔬菜是包菜");}public void pourSauce() {System.out.println("下锅的酱料是辣椒");}
}/*** 炒菜心类*/
public class ConcreteClass_CaiXin extends AbstractClass {public void pourVegetable() {System.out.println("下锅的蔬菜是菜心");}public void pourSauce() {System.out.println("下锅的酱料是蒜蓉");}
}
测试类
public class Client {public static void main(String[] args) {// 炒包菜// 创建对象ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();// 调用炒菜的功能baoCai.cookProcess();}
}
JDK源码
InputStream 类中使用了模板方法模式。在 InputStream 类中定义了多个 read() 方法,如下:
public abstract class InputStream implements Closeable {// 抽象方法,要求子类必须重写public abstract int read() throws IOException;public int read(byte b[]) throws IOException {return read(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {if (b == null) {throw new NullPointerException();} else if (off < 0 || len < 0 || len > b.length - off) {throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int c = read(); // 调用了无参的read方法,该方法是每次读取一个字节数据if (c == -1) {return -1;}b[off] = (byte)c;int i = 1;try {for (; i < len ; i++) {c = read(); // 调用了无参的read方法,该方法是每次读取一个字节数据if (c == -1) {break;}b[off + i] = (byte)c;}} catch (IOException ee) {}return i;}
}
无参的 read() 方法是抽象方法,要求子类必须实现。而 read(byte b[]) 方法调用了 read(byte b[], int off, int len) 方法,所以在此处重点看的方法是带三个参数的方法。在该方法中,可以看到调用了无参的抽象的 read() 方法。
策略模式
抽象策略类:百货公司所有促销活动共同的接口。
public interface Strategy {void show();
}
具体策略角色:每个节日具体的促销活动。
/*** 为春节准备的促销活动A*/
public class StrategyA implements Strategy {public void show() {System.out.println("买一送一");}
}
/*** 为中秋准备的促销活动B*/
public class StrategyB implements Strategy {public void show() {System.out.println("满200元减50元");}
}
/*** 为圣诞准备的促销活动C*/
public class StrategyC implements Strategy {public void show() {System.out.println("满1000元加一元换购任意200元以下商品");}
}
环境角色:用于连接上下文,即把促销活动推销给客户,这里可以理解为销售员。
@Data
@AllA
public class SalesMan {// 聚合策略类对象private Strategy strategy;public SalesMan(Strategy strategy) {this.strategy = strategy;}// 由促销员展示促销活动给用户public void salesManShow() {strategy.show();}
}
测试类:
public class Client {public static void main(String[] args) {// 春节来了,使用春节促销活动SalesMan salesMan = new SalesMan(new StrategyA());// 展示促销活动salesMan.salesManShow();// 中秋节到了,使用中秋节的促销活动salesMan.setStrategy(new StrategyB());// 展示促销活动salesMan.salesManShow();// 圣诞节到了,使用圣诞节的促销活动salesMan.setStrategy(new StrategyC());// 展示促销活动salesMan.salesManShow();}
}
上面在调用 Arrays 的 sort 方法时,第二个参数传递的是 Comparator 接口的子实现类对象。所以 Comparator 充当的是抽象策略角色,而具体的子实现类充当的是具体策略角色。环境角色类 Arrays 应该持有抽象策略的引用来调用。那么,Arrays 类的 sort 方法到底有没有使用 Comparator 子实现类中的 compare() 方法吗?让我们继续查看 TimSort 类的 sort() 方法,代码如下:
class TimSort<T> {static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,T[] work, int workBase, int workLen) {assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;int nRemaining = hi - lo;if (nRemaining < 2)return; // Arrays of size 0 and 1 are always sorted// If array is small, do a "mini-TimSort" with no mergesif (nRemaining < MIN_MERGE) {int initRunLen = countRunAndMakeAscending(a, lo, hi, c);binarySort(a, lo, hi, lo + initRunLen, c);return;}...} private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,Comparator<? super T> c) {assert lo < hi;int runHi = lo + 1;if (runHi == hi)return 1;// Find end of run, and reverse range if descendingif (c.compare(a[runHi++], a[lo]) < 0) { // Descendingwhile (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)runHi++;reverseRange(a, lo, runHi);} else { // Ascendingwhile (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)runHi++;}return runHi - lo;}
}
上面的代码中最终会跑到 countRunAndMakeAscending() 这个方法中。可以看见,只用了 compare 方法,所以在调用 Arrays.sort 方法只传具体 compare 重写方法的类对象就行,这也是 Comparator 接口中必须要子类实现的一个方法。
命令模式
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分隔开,这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储,传递、调用、增加与管理。
抽象命令类:
public interface Command {void execute();
}
具体命令类:
public class OrderCommand implements Command {// 持有接收者对象private SeniorChef receiver;private Order order;public OrderCommand(SeniorChef receiver, Order order) {this.receiver = receiver;this.order = order;}public void execute() {System.out.println(order.getDiningTable() + "桌的订单:");Map<String, Integer> foodDir = order.getFoodDir();Set<String> keys = foodDir.keySet();for (String foodName : keys) {receiver.makeFood(foodName, foodDir.get(foodName));}System.out.println(order.getDiningTable() + "桌的饭准备完毕!!!");}
}/*** 订单类*/
@Data
public class Order {// 餐桌号码private int diningTable;// 所下的餐品及份数private Map<String,Integer> foodDir = new HashMap<>();
}
接收者:资深大厨
public class SeniorChef {public void makeFood(String name,int num) {System.out.println(num + "份" + name);}
}
请求者:服务员
public class Waiter {// 持有多个命令对象private List<Command> commands = new ArrayList<>();public void setCommand(Command cmd) {// 将cmd对象存储到list集合中commands.add(cmd);}// 发起命令功能: 喊 订单来了public void orderUp() {System.out.println("美女服务员:大厨,新订单来了。。。。");for (Command command : commands) {if(command != null) {command.execute();}}}
}
测试类:
public class Client {public static void main(String[] args) {// 创建第一个订单对象Order order1 = new Order();order1.setDiningTable(1);order1.setFood("西红柿鸡蛋面",1);order1.setFood("小杯可乐",2);// 创建第二个订单对象Order order2 = new Order();order2.setDiningTable(2);order2.setFood("尖椒肉丝盖饭",1);order2.setFood("小杯雪碧",1);// 创建厨师对象SeniorChef receiver = new SeniorChef();// 创建命令对象OrderCommand cmd1 = new OrderCommand(receiver, order1);OrderCommand cmd2 = new OrderCommand(receiver, order2);// 创建调用者(服务员对象)Waiter invoker = new Waiter();invoker.setCommand(cmd1);invoker.setCommand(cmd2);// 让服务员发起命令invoker.orderUp();}
}
JDK源码
Runable 是一个典型命令模式,Runnable 担当命令的角色,Thread 充当的是调用者,start 方法就是其执行方法
// 命令接口(抽象命令角色)
public interface Runnable {public abstract void run();
}// 调用者
public class Thread implements Runnable {private Runnable target;public synchronized void start() {if (threadStatus != 0)throw new IllegalThreadStateException();group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}}}private native void start0();
}
/*** jdk Runnable 命令模式* TurnOffThread:属于具体命令*/
public class TurnOffThread implements Runnable{private Receiver receiver;public TurnOffThread(Receiver receiver) {this.receiver = receiver;}public void run() {receiver.turnOFF();}
}
/*** 测试类*/
public class Demo {public static void main(String[] args) {Receiver receiver = new Receiver();TurnOffThread turnOffThread = new TurnOffThread(receiver);Thread thread = new Thread(turnOffThread);thread.start();}
}
职责链模式
请假条类:
@Getter
public class LeaveRequest {// 姓名private String name;// 请假天数private int num;// 请假内容private String content;public LeaveRequest(String name, int num, String content) {this.name = name;this.num = num;this.content = content;}
}
抽象处理者:
public abstract class Handler {protected final static int NUM_ONE = 1;protected final static int NUM_THREE = 3;protected final static int NUM_SEVEN = 7;// 该领导处理的请求天数区间private int numStart;private int numEnd;// 声明后续者(声明上级领导)private Handler nextHandler;public Handler(int numStart) {this.numStart = numStart;}public Handler(int numStart, int numEnd) {this.numStart = numStart;this.numEnd = numEnd;}// 设置上级领导对象public void setNextHandler(Handler nextHandler) {this.nextHandler = nextHandler;}// 各级领导处理请求条的方法protected abstract void handleLeave(LeaveRequest leave);// 提交请求条public final void submit(LeaveRequest leave) {// 该领导进行审批this.handleLeave(leave);if (this.nextHandler != null && leave.getNum() > this.numEnd) {// 提交给上级领导进行审批this.nextHandler.submit(leave);} else {System.out.println("流程结束!");}}
}
具体处理者:小组长、部门经理、总经理
/*** 小组长类,处理1天的假条*/
public class GroupLeader extends Handler {public GroupLeader() {super(0, Handler.NUM_ONE);}protected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("小组长审批:同意");}
}/*** 部门经理类,处理1~3天的假条*/
public class Manager extends Handler {public Manager() {super(Handler.NUM_ONE, Handler.NUM_THREE);}protected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("部门经理审批:同意");}
}/*** 经理类,处理3-7天的假条*/
public class GeneralManager extends Handler {public GeneralManager() {super(Handler.NUM_THREE, Handler.NUM_SEVEN);}protected void handleLeave(LeaveRequest leave) {System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");System.out.println("总经理审批:同意");}
}
测试类:
public class Client {public static void main(String[] args) {// 创建一个请假条对象LeaveRequest leave = new LeaveRequest("小明", 7, "身体不适");// 创建各级领导对象GroupLeader groupLeader = new GroupLeader(); // 小组长Manager manager = new Manager(); // 部门经理GeneralManager generalManager = new GeneralManager(); // 总经理// 设置处理者链groupLeader.setNextHandler(manager);manager.setNextHandler(generalManager);// 小明提交请假申请groupLeader.submit(leave);}
}
模拟实现具体过滤器:
public class FirstFilter implements Filter {@Overridepublic void doFilter(Request request, Response response, FilterChain chain) {System.out.println("过滤器1 前置处理");// 先执行所有request再倒序执行所有responsechain.doFilter(request, response);System.out.println("过滤器1 后置处理");}
}public class SecondFilter implements Filter {@Overridepublic void doFilter(Request request, Response response, FilterChain chain) {System.out.println("过滤器2 前置处理");// 先执行所有request再倒序执行所有responsechain.doFilter(request, response);System.out.println("过滤器2 后置处理");}
}
模拟实现过滤器链 FilterChain:
public class FilterChain {private List<Filter> filters = new ArrayList<>();private int index = 0;// 链式调用public FilterChain addFilter(Filter filter) {this.filters.add(filter);return this;}// 过滤操作public void doFilter(Request request, Response response) {if (index == filters.size()) {return;}Filter filter = filters.get(index);index++;filter.doFilter(request, response, this);}
}
测试类
public class Client {public static void main(String[] args) {Request req = null;Response res = null ;FilterChain filterChain = new FilterChain();filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());filterChain.doFilter(req,res);}
}
状态模式
/*** 电梯接口*/
public interface ILift {// 定义四个电梯状态的常量int OPENING_STATE = 1;int CLOSING_STATE = 2;int RUNNING_STATE = 3;int STOPPING_STATE = 4;// 设置电梯状态的功能void setState(int state);// 电梯操作功能void open();void close();void run();void stop();
}
/*** 电梯类(ILift的子实现类)*/
public class Lift implements ILift {// 声明一个记录当前电梯的状态private int state;public void setState(int state) {this.state = state;}public void open() {switch (state) {case OPENING_STATE:// 什么事都不做break;case CLOSING_STATE:System.out.println("电梯打开了...");// 设置当前电梯状态为开启状态setState(OPENING_STATE);break;case STOPPING_STATE:System.out.println("电梯打开了...");// 设置当前电梯状态为开启状态setState(OPENING_STATE);break;case RUNNING_STATE:// 什么事都不做break;}}public void close() {switch (this.state) {case OPENING_STATE:System.out.println("电梯关门了。。。");//只有开门状态可以关闭电梯门,可以对应电梯状态表来看this.setState(CLOSING_STATE);//关门之后电梯就是关闭状态了break;case CLOSING_STATE://do nothing //已经是关门状态,不能关门break;case RUNNING_STATE://do nothing //运行时电梯门是关着的,不能关门break;case STOPPING_STATE://do nothing //停止时电梯也是关着的,不能关门break;}}public void run() {switch (this.state) {case OPENING_STATE://电梯不能开着门就走//do nothingbreak;case CLOSING_STATE://门关了,可以运行了System.out.println("电梯开始运行了。。。");this.setState(RUNNING_STATE);//现在是运行状态break;case RUNNING_STATE://do nothing 已经是运行状态了break;case STOPPING_STATE:System.out.println("电梯开始运行了。。。");this.setState(RUNNING_STATE);break;}}public void stop() {switch (this.state) {case OPENING_STATE: //开门的电梯已经是是停止的了(正常情况下)//do nothingbreak;case CLOSING_STATE://关门时才可以停止System.out.println("电梯停止了。。。");this.setState(STOPPING_STATE);break;case RUNNING_STATE://运行时当然可以停止了System.out.println("电梯停止了。。。");this.setState(STOPPING_STATE);break;case STOPPING_STATE://do nothingbreak;}}
}
public class Client {public static void main(String[] args) {// 创建电梯对象Lift lift = new Lift();// 设置当前电梯的状态lift.setState(ILift.RUNNING_STATE);// 打开lift.open();lift.close();lift.run();lift.stop();}
}
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
抽象状态类:
public abstract class LiftState {// 声明环境角色类变量protected Context context;public void setContext(Context context) {this.context = context;}// 电梯开启操作public abstract void open();// 电梯关闭操作public abstract void close();// 电梯运行操作public abstract void run();// 电梯停止操作public abstract void stop();
}
具体状态类:电梯开门状态、电梯运行状态 、电梯停止状态、电梯关门状态
/*** 电梯开启状态类*/
public class OpeningState extends LiftState {// 当前状态要执行的方法public void open() {System.out.println("电梯开启。。。");}public void close() {// 修改状态super.context.setLiftState(Context.CLOSING_STATE);// 修改环境super.context.close();}public void run() {}public void stop() {}
}/*** 电梯关闭状态类*/
public class ClosingState extends LiftState {// 当前状态要执行的方法public void close() {System.out.println("电梯门关闭...");}// 关闭 -> 开启public void open() {super.context.setLiftState(Context.OPENING_STATE);super.context.open();}// 关闭 -> 运行public void run() {super.context.setLiftState(Context.RUNNING_STATE);super.context.run();}// 关闭 -> 停止public void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}/*** 电梯运行状态类*/
public class RunningState extends LiftState {// 当前状态要执行的方法public void run() {System.out.println("电梯正在运行...");}// 运行时无法开门@Overridepublic void open() {}// 运行时门是关的@Overridepublic void close() {}// 运行 -> 停止@Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}/*** 电梯停止状态类*/
public class StoppingState extends LiftState {// 当前状态要执行的方法public void stop() {System.out.println("电梯停止了...");}// 停止 -> 开门(委托给ClosingState子类执行)public void open() {super.context.setLiftState(Context.OPENING_STATE);super.context.getLiftState().open();}// 停止 -> 关门(委托给ClosingState子类执行)public void close() {super.context.setLiftState(Context.CLOSING_STATE);super.context.getLiftState().close();}// 停止 -> 运行(委托给ClosingState子类执行)public void run() {super.context.setLiftState(Context.RUNNING_STATE);super.context.getLiftState().run();}
}
环境角色类:
public class Context {// 定义对应状态对象的常量public final static OpeningState OPENING_STATE = new OpeningState();public final static ClosingState CLOSING_STATE = new ClosingState();public final static RunningState RUNNING_STATE = new RunningState();public final static StoppingState STOPPING_STATE = new StoppingState();// 定义一个当前电梯状态变量private LiftState liftState;public LiftState getLiftState() {return liftState;}// 设置当前状态对象public void setLiftState(LiftState liftState) {this.liftState = liftState;// 设置当前状态对象中的Context对象this.liftState.setContext(this);}public void open() {this.liftState.open();}public void close() {this.liftState.close();}public void run() {this.liftState.run();}public void stop() {this.liftState.stop();}
}
测试类
public class Client {public static void main(String[] args) {// 创建环境角色对象Context context = new Context();// 设置当前电梯装填context.setLiftState(new ClosingState());context.open();context.run();context.close();context.stop();}
}
观察者模式
抽象观察者:
public interface Observer {void update(String message);
}
具体观察者:微信用户,实现了更新的方法
public class WeiXinUser implements Observer {private String name;public WeiXinUser(String name) {this.name = name;}public void update(String message) {System.out.println(name + "-" + message);}
}
抽象主题角色:
public interface Subject {// 添加订阅者(添加观察者对象)void attach(Observer observer);// 删除订阅者void detach(Observer observer);// 通知订阅者更新消息void notify(String message);
}
具体主题角色:微信公众号,里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法
public class SubscriptionSubject implements Subject {// 定义一个集合,用来存储多个观察者对象private List<Observer> weiXinUserList = new ArrayList<>();public void attach(Observer observer) {weiXinUserList.add(observer);}public void detach(Observer observer) {weiXinUserList.remove(observer);}public void notify(String message) {for (Observer observer : weiXinUserList) {// 调用观察者对象中的update方法observer.update(message);}}
}
测试类:
public class Client {public static void main(String[] args) {// 1,创建公众号对象SubscriptionSubject subject = new SubscriptionSubject();// 2,订阅公众号subject.attach(new WeiXinUser("孙悟空"));subject.attach(new WeiXinUser("猪悟能"));subject.attach(new WeiXinUser("沙悟净"));// 3,公众号更新,发出消息给订阅者(观察者对象)subject.notify("传智黑马的专栏更新了!");}
}
警察抓小偷也可以使用观察者模式来实现,警察是观察者,小偷是被观察者
小偷是一个被观察者,所以需要继承 Observable 类:
@Data
public class Thief extends Observable {private String name;public Thief(String name) {this.name = name;}public void steal() {System.out.println("小偷:我偷东西了,有没有人来抓我!!!");super.setChanged(); // changed = truesuper.notifyObservers();}
}
警察是一个观察者,所以需要让其实现 Observer 接口:
@Data
public class Policemen implements Observer {private String name;public Policemen(String name) {this.name = name;}@Overridepublic void update(Observable o, Object arg) {System.out.println("警察:" + ((Thief) o).getName() + ",我已经盯你很久了!!!");}
}
客户端:
public class Client {public static void main(String[] args) {// 创建小偷对象Thief t = new Thief("隔壁老王");// 创建警察对象Policemen p = new Policemen("小李");// 让警察盯着小偷t.addObserver(p);// 小偷偷东西t.steal();}
}
中介者模式
抽象中介者类:
public abstract class Mediator {public abstract void contact(String message, Person person);
}
抽象同事类:
@AllArgsConstructor
public abstract class Person {protected String name;protected Mediator mediator;
}
具体同事类:房主、房客
/*** 具体的同事角色类 - 房主*/
public class HouseOwner extends Person {public HouseOwner(String name, Mediator mediator) {super(name, mediator);}// 和中介联系(沟通)public void contact(String message) {mediator.contact(message,this);}// 获取信息public void getMessage(String message) {System.out.println("房主" + name + "获取到的信息是:" + message);}
}/*** 具体的同事角色类 - 房客*/
public class Tenant extends Person {public Tenant(String name, Mediator mediator) {super(name, mediator);}// 和中介联系(沟通)public void contact(String message) {mediator.contact(message,this);}// 获取信息public void getMessage(String message) {System.out.println("租房者" + name + "获取到的信息是:" + message);}
}
具体中介者角色:中介机构
@Data
public class MediatorStructure extends Mediator {// 聚合房主和房客对象private HouseOwner houseOwner;private Tenant tenant;public void contact(String message, Person person) {if (person == houseOwner) {tenant.getMessage(message);} else {houseOwner.getMessage(message);}}
}
测试类:
public class Client {public static void main(String[] args) {// 中介者对象MediatorStructure mediator = new MediatorStructure();// 租房者对象Tenant tenant = new Tenant("李四", mediator);// 房主对象HouseOwner houseOwner = new HouseOwner("张三", mediator);// 中介者要知道具体的房主和租房者mediator.setTenant(tenant);mediator.setHouseOwner(houseOwner);tenant.contact("我要租三室的房子!!!");houseOwner.contact("我这里有三室的房子,你要租吗?");}
}
迭代器模式
实体类:
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Student {private String name;private String number;
}
抽象迭代器角色:拥有 hasNext 和 next 方法
public interface StudentIterator {// 判断是否还有元素boolean hasNext();// 获取下一个元素Student next();
}
具体迭代器角色:重写抽象方法
public class StudentIteratorImpl implements StudentIterator {private final List<Student> list;private int position = 0; // 记录遍历时的位置public StudentIteratorImpl(List<Student> list) {this.list = list;}public boolean hasNext() {return position < list.size();}public Student next() {// 从集合中获取指定位置的元素return list.get(position++);}
}
抽象聚合角色:包含添加元素,删除元素,获取迭代器对象的方法
public interface StudentAggregate {// 添加学生功能void addStudent(Student stu);// 删除学生功能void removeStudent(Student stu);// 获取迭代器对象功能StudentIterator getStudentIterator();
}
具体聚合角色:重写抽象方法
public class StudentAggregateImpl implements StudentAggregate {private List<Student> list = new ArrayList<>();public void addStudent(Student stu) {list.add(stu);}public void removeStudent(Student stu) {list.remove(stu);}// 获取迭代器对象public StudentIterator getStudentIterator() {return new StudentIteratorImpl(list);}
}
测试类
public class Client {public static void main(String[] args) {// 创建聚合对象StudentAggregateImpl aggregate = new StudentAggregateImpl();// 添加元素aggregate.addStudent(new Student("张三", "001"));aggregate.addStudent(new Student("李四", "002"));aggregate.addStudent(new Student("王五", "003"));aggregate.addStudent(new Student("赵六", "004"));// 遍历聚合对象// 1,获取迭代器对象StudentIterator iterator = aggregate.getStudentIterator();// 2,遍历while (iterator.hasNext()) {// 3,获取元素Student student = iterator.next();System.out.println(student);}}
}
ArrayList具体实现
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {public Iterator<E> iterator() {return new Itr();}private class Itr implements Iterator<E> {int cursor; // 下一个要返回元素的索引int lastRet = -1; // 上一个返回元素的索引int expectedModCount = modCount;Itr() {}//判断是否还有元素public boolean hasNext() {return cursor != size;}//获取下一个元素public E next() {checkForComodification();int i = cursor;if (i >= size)throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length)throw new ConcurrentModificationException();cursor = i + 1;return (E) elementData[lastRet = i];}...
}
访问者模式
抽象访问者类:给宠喂食
public interface Person {// 喂食宠物猫void feed(Cat cat);// 喂食宠物狗void feed(Dog dog);
}
具体访问者角色:主人、其他人,都实现 Person 接口
/*** 具体访问者角色类(自己)*/
public class Owner implements Person {public void feed(Cat cat) {System.out.println("主人喂食猫");}public void feed(Dog dog) {System.out.println("主人喂食狗");}
}
/*** 具体访问者角色类(其他人)*/
public class Someone implements Person {public void feed(Cat cat) {System.out.println("其他人喂食猫");}public void feed(Dog dog) {System.out.println("其他人喂食狗");}
}
抽象元素角色:被喂食的动物抽象类
public interface Animal {// 接受访问者访问的功能void accept(Person person);
}
具体元素角色:狗、猫
/*** 具体元素角色类(宠物狗)*/
public class Dog implements Animal {public void accept(Person person) {person.feed(this); // 访问者给宠物狗喂食System.out.println("好好吃,汪汪汪。。。");}
}
/*** 具体元素角色类(宠物猫)*/
public class Cat implements Animal {public void accept(Person person) {person.feed(this); // 访问者给宠物猫喂食System.out.println("好好吃,喵喵喵。。。");}
}
对象结构角色:此案例中是主人的家
public class Home {// 声明一个集合对象,用来存储元素对象private List<Animal> nodeList = new ArrayList<>();// 添加元素功能public void add(Animal animal) {nodeList.add(animal);}public void action(Person person) {// 遍历集合,获取每一个元素,让访问者访问每一个元素for (Animal animal : nodeList) {animal.accept(person);}}
}
测试类
public class Client {public static void main(String[] args) {// 创建Home对象Home home = new Home();// 添加元素到Home对象中home.add(new Dog());home.add(new Cat());// 创建主人对象Owner owner = new Owner();// 让主人喂食所有的宠物home.action(owner);}
}
动态分派:通过方法的重写支持动态分派
public class Animal {public void execute() {System.out.println("Animal");}
}public class Dog extends Animal {@Overridepublic void execute() {System.out.println("dog");}
}public class Cat extends Animal {@Overridepublic void execute() {System.out.println("cat");}
}public class Client {public static void main(String[] args) {Animal a = new Animal();a.execute();Animal d = new Dog();d.execute();Animal c = new Cat();c.execute();}
}
Java 编译器在编译时期并不总是知道哪些代码会被执行,因为编译器仅仅知道对象的静态类型,而不知道对象的真实类型;而方法的调用则是根据对象的真实类型,而不是静态类型。
静态分派:通过方法的重载支持静态分派
public class Animal {}public class Dog extends Animal {}public class Cat extends Animal {}public class Execute {public void execute(Animal a) {System.out.println("Animal");}public void execute(Dog d) {System.out.println("dog");}public void execute(Cat c) {System.out.println("cat");}
}public class Client {public static void main(String[] args) {Animal a = new Animal();Animal a1 = new Dog();Animal a2 = new Cat();// 静态分派根据静态类型决定Execute exe = new Execute();exe.execute(a);exe.execute(a1);exe.execute(a2);}
}
public class Animal {public void accept(Execute exe) {// 2.传递了this给Execute,根据静态类型进行方法重载实现静态分派exe.execute(this);}
}public class Dog extends Animal {public void accept(Execute exe) {exe.execute(this);}
}public class Cat extends Animal {public void accept(Execute exe) {exe.execute(this);}
}public class Execute {public void execute(Animal a) {System.out.println("animal");}public void execute(Dog d) {System.out.println("dog");}public void execute(Cat c) {System.out.println("cat");}
}public class Client {public static void main(String[] args) {Animal a = new Animal();Animal d = new Dog();Animal c = new Cat();Execute exe = new Execute();// 1.exe传递给Animal类型的变量调用,方法重写实现动态分派a.accept(exe);d.accept(exe);c.accept(exe);}
}
备忘录模式
发起人角色:游戏角色
/*** 游戏角色类(属于发起人角色)*/
@Data
public class GameRole {private int vit; // 生命力private int atk; // 攻击力private int def; // 防御力// 初始化内部状态public void initState() {this.vit = 100;this.atk = 100;this.def = 100;}// 战斗public void fight() {this.vit = 0;this.atk = 0;this.def = 0;}// 保存角色状态功能public RoleStateMemento saveState() {return new RoleStateMemento(vit, atk, def);}// 恢复角色状态public void recoverState(RoleStateMemento roleStateMemento) {// 将备忘录对象中存储的状态赋值给当前对象的成员this.vit = roleStateMemento.getVit();this.atk = roleStateMemento.getAtk();this.def = roleStateMemento.getDef();}// 展示状态功能public void stateDisplay() {System.out.println("角色生命力:" + vit);System.out.println("角色攻击力:" + atk);System.out.println("角色防御力:" + def);}
}
备忘录角色:用于存储发起人的内部状态,因此拥有属性和发起人一样
@Data
@AllArgsConstructor
public class RoleStateMemento {private int vit; // 生命力private int atk; // 攻击力private int def; // 防御力
}
管理者角色:用于管理备忘录角色
@Data
public class RoleStateCaretaker {private RoleStateMemento roleStateMemento;
}
测试类:
public class Client {public static void main(String[] args) {System.out.println("---------------大战boss前-----------------");// 创建游戏角色对象GameRole gameRole = new GameRole();gameRole.initState(); // 初始化状态操作gameRole.stateDisplay();// 将该游戏角色内部状态进行备份// 创建管理者对象RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();roleStateCaretaker.setRoleStateMemento(gameRole.saveState());System.out.println("---------------大战boss后-----------------");// 损耗严重gameRole.fight();gameRole.stateDisplay();System.out.println("---------------恢复之前的状态-----------------");gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());gameRole.stateDisplay();}
}
备忘录接口:对外提供窄接口,标识接口,没有任何方法
public interface Memento {
}
发起人角色:游戏角色,在内部定义备忘录内部类 RoleStateMemento(私有),对自己提供宽接口,但外部无法访问
@Data
public class GameRole {private int vit; // 生命力private int atk; // 攻击力private int def; // 防御力// 初始化内部状态public void initState() {this.vit = 100;this.atk = 100;this.def = 100;}// 战斗public void fight() {this.vit = 0;this.atk = 0;this.def = 0;}// 保存角色状态功能public Memento saveState() {return new RoleStateMemento(vit, atk, def);}// 恢复角色状态public void recoverState(Memento memento) {RoleStateMemento roleStateMemento = (RoleStateMemento) memento;// 将备忘录对象中存储的状态赋值给当前对象的成员this.vit = roleStateMemento.getVit();this.atk = roleStateMemento.getAtk();this.def = roleStateMemento.getDef();}// 展示状态功能public void stateDisplay() {System.out.println("角色生命力:" + vit);System.out.println("角色攻击力:" + atk);System.out.println("角色防御力:" + def);}// 对发起者宽接口,对其他类窄接口@Data@AllArgsConstructorprivate static class RoleStateMemento implements Memento {private int vit; // 生命力private int atk; // 攻击力private int def; // 防御力}
}
管理者角色:这个类聚合的是 Memento 接口,只是个标识接口,因此该角色无法更改备忘录的内容
@Data
public class RoleStateCaretaker {private Memento memento;
}
测试类:
public class Client {public static void main(String[] args) {System.out.println("---------------大战boos前-----------------");// 创建游戏角色对象GameRole gameRole = new GameRole();gameRole.initState(); // 初始化状态操作gameRole.stateDisplay();// 将该游戏角色内部状态进行备份// 创建管理者对象RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();roleStateCaretaker.setMemento(gameRole.saveState());System.out.println("---------------大战boos后-----------------");// 损耗严重gameRole.fight();gameRole.stateDisplay();System.out.println("---------------恢复之前的状态-----------------");gameRole.recoverState(roleStateCaretaker.getMemento());gameRole.stateDisplay();}
}
解释器模式
抽象表达式:
public abstract class AbstractExpression {public abstract int interpret(Context context);
}
终结符表达式:变量表达式
@AllArgsConstructor
public class Variable extends AbstractExpression {// 声明存储变量名的成员变量private String name;public int interpret(Context context) {// 直接返回变量的值return context.getValue(this);}@Overridepublic String toString() {return name;}
}
非终结表达式:加法表达式、减法表达式
/*** 加法表达式类*/
@AllArgsConstructor
public class Plus extends AbstractExpression {// +号左边的表达式private AbstractExpression left;// +号右边的表达式private AbstractExpression right;@Overridepublic int interpret(Context context) {// 将左边表达式的结果和右边表达式的结果进行相加return left.interpret(context) + right.interpret(context);}@Overridepublic String toString() {return "(" + left.toString() + " + " + right.toString() + ")";}
}
/*** 减法表达式类*/
@AllArgsConstructor
public class Minus extends AbstractExpression {// -号左边的表达式private AbstractExpression left;// -号右边的表达式private AbstractExpression right;@Overridepublic int interpret(Context context) {// 将左边表达式的结果和右边表达式的结果进行相减return left.interpret(context) - right.interpret(context);}@Overridepublic String toString() {return "(" + left.toString() + " - " + right.toString() + ")";}
}
环境角色类:
public class Context {// 定义一个map集合,用来存储变量及对应的值private Map<Variable, Integer> map = new HashMap<>();// 添加变量的功能public void assign(Variable var, Integer value) {map.put(var, value);}// 根据变量获取对应的值public int getValue(Variable var) {return map.get(var);}
}
测试类:
public class Client {public static void main(String[] args) {// 创建环境对象Context context = new Context();// 创建多个变量对象Variable a = new Variable("a");Variable b = new Variable("b");Variable c = new Variable("c");Variable d = new Variable("d");// 将变量存储到环境对象中context.assign(a, 1);context.assign(b, 2);context.assign(c, 3);context.assign(d, 4);// 获取抽象语法树 a + b - c + dAbstractExpression expression = new Plus(a, new Minus(new Minus(b, c), d));// 解释(计算)int result = expression.interpret(context);System.out.println(expression + " = " + result);}
}
相关文章:

java设计模式之行为型模式(11种)
行为型模式 行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象型模式,前者采用继承机制来在类间分派…...

微服务系列一:基础拆分实践
目录 前言 一、认识微服务 1.1 单体架构 VS 微服务架构 1.2 微服务的集大成者:SpringCloud 1.3 微服务拆分原则 1.4 微服务拆分方式 二、微服务拆分入门步骤 :以拆分商品模块为例 三、服务注册订阅与远程调用:以拆分购物车为例 3.1 …...

leetcode 1470.重新排列数组
1.题目要求: 2.题目代码: class Solution { public:vector<int> shuffle(vector<int>& nums, int n) {vector<int> x_array(nums.begin(),nums.begin() n);vector<int> y_array(nums.begin() n,nums.end());int x_index 0;int y_index 0;for…...

windows在两台机器上测试 MySQL 集群实现实时备份
在两台机器上测试 MySQL 集群实现实时备份的基本步骤: 一、环境准备 机器配置 确保两台机器(假设为服务器 A 和服务器 B)能够互相通信,例如它们在同一个局域网内,并且开放了 MySQL 通信所需的端口(默认是 …...

点晴模切ERP系统助力模切企业转型升级之路
随着我国制造业规模不断扩大,中国制造业已经从高速扩张转向深入挖潜的关键阶段。数字化转型不仅有助于提升企业的生产效率和管理水平,还能有效应对市场竞争,实现可持续发展。在数字化转型的过程中,企业资源规划(ERP&am…...

redis修改配置文件配置密码开启远程访问后台运行
编辑 Redis 配置文件 编辑 /etc/redis/redis.conf,设置必要的参数。 sudo vim /etc/redis/redis.conf设置后台运行: 找到以下行,将 no 改为 yes: daemonize yes设置密码: 找到以下行,取消注释并设置密码为…...

市场分化!汽车零部件「变天」
全球汽车市场的动荡不安,还在持续。 本周,全球TOP20汽车零部件公司—安波福(Aptiv)发布2024年第三季度财报显示,三季度公司经调整后确认收入同比下降6%;按照区域市场来看,也几乎是清一色的下滑景…...

SCSS在Vue中的用法
SCSS在Vue中的用法 一、安装相关依赖1、安装sass - loader和node - sass(或dart - sass) 二、在组件中使用SCSS1、单文件组件(.vue)中的样式使用2、**全局样式使用SCSS**3、在组件中使用变量和混入(Mixins)…...

CPU用户时间百分比
在计算机系统中,"CPU用户时间百分比(CPU User Time)"是一个性能监控指标,它描述了CPU在用户模式下执行的累积时间与总的CPU时间的比例。这个指标可以帮助我们了解系统在执行用户态程序时的负载情况。下面是一些关于CPU用…...

RN中的StyleSheet
一、RN中样式的特点 RN的样式和前端的CSS的样式有一些区别。主要如下: RN中的样式 前端的CSS 继承性 没有继承性 有继承性 命名 fontSize(小驼峰命名) font-size 尺寸单位 with: 100 With: 100px 特殊的样式名 marginHorizontal…...

Swift 开发教程系列 - 第1章:Swift 简介与开发环境配置
在开始开发 Swift 应用之前,了解 Swift 语言的背景和设置开发环境非常重要。接下来,我们将逐步介绍 Swift 的基本概念,并带你完成开发环境的安装和项目创建。 1.1 Swift 简介 Swift 是由 Apple 开发的一种现代化编程语言,于 201…...

躺平成长-下一个更新的数据(躺平成长数据显示核心)
旭日图(Sunburst Chart)是一种用于展示具有层次结构数据的可视化图表。 开源竞争: (当你无法掌握技术的时候,就开源这个技术,培养出更多的技术依赖,让更多的人帮助你完善你的技术,那…...

你们接口怎么测?有没有完完整整的把一个接口测下来?
面试官在问到这道问题的时候,我们应该这么去回答,根据自己技术掌握的水准进行由浅入深的回答。 基础: 我们接口测试之前,开发都会有一份接口文档给到我们,我们要分析接口中的入参和响应。 针对入参的参数类型和参数…...

Pinia-状态管理
Pinia-状态管理 特点: 1. 轻量和模块化 Pinia 是一个轻量级的状态管理库,支持模块化管理,即可以将应用的状态分成多个 store 以实现更好的组织。使用 Pinia,可以定义多个 store,每个 store 都是一个独立的模块&#x…...

IP系列之bscan讨论
1、做Bcan前首先要确定ip_vender是否已经在phy_level做好了bscan_chian??? 若已经做好,那么vender会给一个XXX.bsdl文件,结合详细的ip文档指导手册,确定bscan_chain是在内部的tap下挂着,还是单…...

Centos安装配置Jenkins
下载安装 注意:推荐的LTS版本对部分插件不适配,直接用最新的版本,jenkins还需要用到git和maven,服务器上已经安装,可查看参考文档[1]、[2],本次不再演示 访问开始使用 Jenkins 下载jenkins 上传至服务器…...

创新医疗突破:新型穿刺器显著提高手术安全性与效率
据QYResearch调研团队最新报告“中国穿刺器市场报告2023-2029”显示,预计2029年中国穿刺器市场规模将达到18.5亿美元,未来几年年复合增长率CAGR为18.1%。 如上图表/数据,摘自QYResearch最新报告“中国穿刺器市场研究报告2023-2029. 如上图表/…...

【MySQL】可重复读级别下基于Next Key Lock解决幻读
昨天读到了一篇文章[1],里面讲,面试官说mysql的可重复读级别下有解决幻读的方式,最后公布了答案,是在sql后面加for update。这么说倒是没错,但是这种问法给我一种奇怪的感觉,因为for update无论在哪个隔离级…...

【安全性分析】正式安全分析与非正式安全分析
安全性分析-系列文章目录 第一章 【安全性分析】正式安全分析与非正式安全分析 第二章 【安全性分析】BAN逻辑 (BAN Logic) 文章目录 安全性分析-系列文章目录前言一、正式安全分析1. 理想化模型(如随机预言机模型)2. 标准模型(Standard Model)3. 形式化验证4. 数学证明二…...

【项目开发】高校思政课程实践任务平台—数据库设计
未经许可,不得转载。 文章目录 1、项目需求2、数据库选型3、概念数据模型设计3.1、实体及属性3.2、实体关系3.3、补充说明4、数据库语句4.1、数据库对象创建语句4.2、功能实现的SQL语句4.3、视图创建语句4.4、触发器创建语句5、安全性考虑5.1、用户认证和授权5.2、数据传输安全…...

计算机网络安全应该学习哪些知识?
计算机网络安全是一个广泛而深入的领域,要成为一名专业的网络安全专家,需要系统地学习多个方面的知识。以下是一些关键的学习方向: 一、基础知识计算机网络:学习OSI、TCP/IP模型,网络协议,网络设备工作原理…...

logrotate工具强制日志轮询
说明: 1、通过定时任务logrotate工具每天强制日志轮询并压缩,节省存储空间。 参数说明: 1)/opt/yolov5/logs/.log: 是指要轮转日志文件的路径和名称。 是一个通配符,表示匹配以*.log结尾文件名。 2)daily: 是指日志文件每天轮转一次。 3)dateext: 是指轮转的日志文件名中…...

微服务系列三:微服务核心——网关路由
目录 前言 一、登录存在的问题归纳 二、*微服务网关整体方案 三、认识微服务网关 四、网关鉴权实现 五、OpenFeign微服务间用户标识信息传递实现 六、微服务网关知识追问巩固 前言 本篇文章具体讲解微服务中网关的实现逻辑、用于解决什么样的问题。其中标题中标注* 涉…...

【系统架构设计师】2023年真题论文: 论边云协同的设计与实现(包括解题思路和素材)
更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 真题题目(2023年 试题4)解题思路边云协同概念和架构边云协同的关键技术边云协同的设计与实现案例分析论文素材参考真题题目(2023年 试题4) 边云协同是指将边缘计算和云计算相结合,实现边缘设备与云端资源之间…...

vue3记录(第一版)
vue2与vue3的区别 vue2属于选项式API,vue3属于组合式API setup概述 setup是vue3中一个新的配置项,值是一个函数,组件中所用到的数据,方法,计算属性,监视等等,均配置在setup中 vue3中的setup和vue2的data,methods之间有什么关系呢? 因为setup比data解析的早,所以在data中可以…...

R 语言数据导入与导出
R 语言数据导入与导出 数据的导入和导出是数据处理中的重要步骤。R 语言提供了多种方法来读取和写入不同格式的数据文件,包括 CSV、Excel、JSON、SQL 数据库等。本文将介绍如何在 R 语言中进行数据的导入和导出。 1. 导入数据 1.1 读取 CSV 文件 CSV(C…...

kubectl常用命令简介
在之前浅谈Kubernetes集群架构 中介绍了kube-apiserver是提供k8s对内或对外的api请求的唯一入口,本文介绍的 kubectl 是官方的CLI命令行工具,用于与 apiserver 进行通信,将用户在命令行输入的命令,组织并转化为 apiserver 能识别的…...

【小白学机器学习31】 大数定律,中心极限定理,标准正态分布与概率的使用
目录 1 正态分布相关的2个相关定理 1.1 大数定律:(证明了)分布的稳定性 1.2 中心极限定理:(证明了)分布的收敛性 2 使用标准差和概率的2种思路 2.1 标准正态分布的曲线 2.2 两种使用方式 2.3 第1种:按整数倍标准差δ 作为标准使用 2.…...

Go语言基础语法
一、创建工程 说明: (1)go.mod文件是go项目依赖管理文件,相当于前端的package.json,也就是Java项目中的Maven的pom.xml。 二、打印数据到控制台 (1)引入fmt (2)使用fmt…...

CSS层叠/CSS变量和!important的使用
layer components {:root {--theme: red;font-family: serif !important;} } CSS Layers CSS Layers 是一种用于管理和组织样式规则的新机制。它允许开发者定义不同的样式层,以便更好地控制样式的优先级和覆盖关系。通过使用 layer 规则,开发者可以将样…...