设计模式
行为型模式
重点关注对象之间是如何通信的
模板方法模式
定义了一个算法架构,允许子类为一个或者多个步骤实现
模板方法在子类不改变算法结构的情况下,重新定义算法某些步骤
实现算法的不变部分,并将可变的空间留给子类完成
子类中公共的行为抽出出来并封装到一个公共的父类中,避免代码重复
设计抽象类,其中约定一个流程,流程控制交由flag函数进行控制,实现的子类可以重写这个函数进行对于父类流程改变
public abstract class AClass {
public final void makeClass() {
makePPT();
makeVideo();
if(flag()) {
makeJava();
doJava();
}
}
public final void makePPT() {
System.out.println("制作PPT");
}
public final void makeVideo() {
System.out.println("制作Video");
}
public final void makeJava() {
System.out.println("编写JAVA");
}
protected boolean flag() {
return false;
}
public abstract void doJava();
}实现类,重写flag方法
public class JavaClass extends AClass{
private boolean flag;
public JavaClass(boolean flag) {
this.flag = flag;
}
@Override
protected boolean flag() {
return flag;
}
@Override
public void doJava() {
System.out.println("设计模式代码");
}
}实际调用传入true,那么在制作课程的时候执行java相关的业务
public class Main {
public static void main(String[] args) {
AClass javaClass = new JavaClass(true);
javaClass.makeClass();
}
}这样我们实现子类的时候可以自定义父类模板流程,进行灵活增加删除一些流程
迭代器模式
提供方法,顺序访问集合中的各个元素,而不暴露对象的内部表示
为遍历不同的集合结构提供了统一的接口,分离了集合对象的遍历行为
迭代器接口,使用泛型作为拓展
public interface Iterator<T> {
boolean hasNext();
T next();
}书籍迭代器实现
public class BookIterator implements Iterator<Book>{
private Book[] books;
private int index = 0;
public BookIterator(Book[] books) {
this.books = books;
}
@Override
public boolean hasNext() {
return index < books.length && books[index] != null;
}
@Override
public Book next() {
return books[index++];
}
}通过创建和传入books数组,即可通过迭代器获取各个元素
public interface Library {
Iterator<Book> createIterator();
}public class BookLibrary implements Library {
private Book[] books;
public BookLibrary(Book[] books) {
this.books = books;
}
@Override
public Iterator<Book> createIterator() {
return new BookIterator(books);
}
}public class Main {
public static void main(String[] args) {
Book[] books = {new Book(), new Book(), new Book()};
Library library = new BookLibrary(books);
Iterator<Book> iterator = library.createIterator();
while (iterator.hasNext()) {
Book book = iterator.next();
System.out.println(book);
}
}
}策略模式
定义了算法,分别封装起来,他们之间可以相互替换,让算法的变化不会影响到使用算法的用户
如果有大量的if-else可以通过策略模式进行替换
提报算法的保密性
现有一个算法的接口,传入两个参数
public interface Strategy {
int operator(int n1, int n2);
}加法实现
public class Add implements Strategy {
@Override
public int operator(int n1, int n2) {
return n1 + n2;
}
}减法实现
public class Sub implements Strategy {
@Override
public int operator(int n1, int n2) {
return n1 - n2;
}
}策略类,其中有算法的接口对象
public class Operation {
private Strategy strategy;
public Operation(Strategy strategy) {
this.strategy = strategy;
}
public int execute(int n1, int n2) {
return strategy.operator(n1, n2);
}
}使用的时候传入对应算法实现即可
public class Main {
public static void main(String[] args) {
Operation operation = new Operation(new Add());
System.out.println(operation.execute(1, 2));
}
}解释器模式
通过给定的语言,定义它的语法和行为,并定义解释器,用这个解释器来解释语言中的句子
为解释一种语言,而为语言创建的解释器
某个类型的语言触发频次够高,比如处理日志和不同日志格式
解释器接口
public interface Expression {
boolean interpret(String context);
}解释器实现,传入带解释的数据,实现中实现解释逻辑
public class TerminalExpression implements Expression{
private String data;
public TerminalExpression(String data) {
this.data = data;
}
@Override
public boolean interpret(String context) {
return context.contains(data);
}
}public class Main {
public static void main(String[] args) {
Expression expression = new TerminalExpression("hello");
System.out.println(expression.interpret("hello world"));
}
}观察者模式
当存在一对多关系的时候,可以使用观察者模式
比如,当一个对象被修改的时候,则会自动通知依赖他的对象
让对多个观察者对象同时监听某一个主题对象,当主题对象发生改变的时候,它所有依赖者(观察者)都会收到通知并更新
主题类
设计一个主题类,其中包含了观察者对象列表,观察对象state,以及绑定方法(将观察者添加到观察者列表中)
在state的set方法上设立通知的方法,当set观察对象被修改的时候,发出通知,去依次执行观察者中的方法
public class Subject {
private List<Observer> observerList = new ArrayList<>();
private int state;
public void bind(Observer observer) {
observerList.add(observer);
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
public void notifyObservers() {
for (Observer observer : observerList) {
observer.update();
}
}
}观察者抽象类
由对应的抽象方法供通知方法调用,交由子类实现
public abstract class Observer {
protected Subject subject;
public abstract void update();
}观察者实现
在构造方法中传入主题对象,由主题对象进行对于观察者的绑定,实现主题通知观察者的方法
public class HexObserver extends Observer {
public HexObserver(Subject subject) {
this.subject = subject;
this.subject.bind(this);
}
@Override
public void update() {
System.out.println("转换为16进制:" + Integer.toHexString(subject.getState()));
}
}调用:创建主题对象,创建观察者并绑定到主题上,当主题监听字段发送改变的时候触发通知调用观察者更新方法
public class Main {
public static void main(String[] args) {
Subject subject = new Subject();
new HexObserver(subject);
System.out.println("状态值为:15");
subject.setState(15);
}
}备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态
现在有一个文本编辑器,可以编辑并提供撤销功能
// 1. Memento(存储编辑器状态)
public class TextMemento {
private final String content; // 状态保存的内容
public TextMemento(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}// 2. Originator(需要保存状态的类)
public class TextEditor {
private String content;
public void write(String text) {
this.content = text;
}
public String getContent() {
return content;
}
// 创建备忘录(保存当前状态)
public TextMemento save() {
return new TextMemento(this.content);
}
// 恢复状态
public void restore(TextMemento memento) {
this.content = memento.getContent();
}
}// 3. Caretaker(管理备忘录)
public class HistoryManager {
private Stack<TextMemento> history = new Stack<>();
public void save(TextMemento memento) {
history.push(memento);
}
public TextMemento undo() {
if (!history.isEmpty()) {
return history.pop(); // 返回上一个状态
}
return null;
}
}客户端调用
public class Client {
public static void main(String[] args) {
// 初始化
TextEditor editor = new TextEditor();
HistoryManager history = new HistoryManager();
// 编辑并保存
editor.write("Hello"); // 第一次编辑
history.save(editor.save()); // 保存状态1
editor.write("Hello World"); // 第二次编辑
history.save(editor.save()); // 保存状态2
editor.write("Hello Java"); // 第三次编辑
System.out.println("Current Content: " + editor.getContent()); // "Hello Java"
// 撤销一次(回到 "Hello World")
editor.restore(history.undo());
System.out.println("After Undo: " + editor.getContent()); // "Hello World"
// 再撤销一次(回到 "Hello")
editor.restore(history.undo());
System.out.println("After 2nd Undo: " + editor.getContent()); // "Hello"
}
}命令模式
将一个请求封装为一个对象,从而可以用不同的请求对于客户进行参数化,解决了应用程序中对象的职责以及它们之间的通信方式
在软件系统中,行为请求者和行为实现者通常是一种紧耦合的关系,但在某些场合,比如需要对行为进行记录,撤销或者重做,事务等处理的时候,这种无法抵御变化的紧耦合的设计就不太合适
请求调用者和行为实现者需要解耦,使得调用者和行为实现者不直接交互
由一个类型的股票,可以买入卖出
public class Stock {
private String name;
private int count = 10;
public void buy() {
System.out.println("购买:" + name + "股票-" + count);
}
public void sell() {
System.out.println("卖出:" + name + "股票-" + count);
}
}现在有命令接口
public interface Order {
void execute();
}实现命令
public class BuyStock implements Order {
private Stock stock;
public BuyStock(Stock stock) {
this.stock = stock;
}
@Override
public void execute() {
stock.buy();
}
}public class SellStock implements Order{
private Stock stock;
public SellStock(Stock stock) {
this.stock = stock;
}
@Override
public void execute() {
stock.sell();
}
}中间的代理者,可以向其中传入命令,暴露方法统一执行
public class Broker {
List<Order> orders = new ArrayList<Order>();
public void takeOrder(Order order) {
orders.add(order);
}
public void placeOrder() {
for (Order order : orders) {
order.execute();
}
orders.clear();
}
}public class Main {
public static void main(String[] args) {
Stock stock = new Stock();
Broker broker = new Broker();
broker.takeOrder(new BuyStock(stock));
broker.takeOrder(new SellStock(stock));
broker.placeOrder();
}
}中介者模式
用于降低多个对象之间通信的复杂性,提供一个中介类,通常处理不同类之间的通信,并支持松耦合,使代码易于维护
中介者类
public class Role {
public static void work(User user, String message) {
System.out.println("Role work");
System.out.println("User: " + user.getName());
System.out.println("Message: " + message);
}
}在User中调用中介者的方法
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void sendMessage(String message) {
Role.work(this, message);
}
}使用,通过用户调用中介者方法实现业务功能,中介者负责实际业务功能
public class Main {
public static void main(String[] args) {
User user = new User("张三");
User user01 = new User("李四");
user.sendMessage("睡觉");
user01.sendMessage("工作");
}
}责任链模式
为请求创建一个接收者对象的链,对请求的发送者和接收者进行解耦
在这种模式中,通常每个接收者都包含另一个接受者的引用。如果一个对象不能处理该请求,那么它就会把相同的请求传给下一个接收者,以此类推。
避免请求者和请求者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成为一条链,并沿着这条链传递请求,直到有对象处理它为止。
职责链上的处理者负责处理请求,客户只需要将请求发送到责任链上即可,无需关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求处理器解耦了。
详细构思
这个部分我们后续的项目会用到,故好好学学
现在需要开发一个请假流程控制系统,请假一天以下只需要小组长同意即可,1-3天还需要部门经理同意,请求3-7天还需要总经理同意
/**
* 请假条类
*/
@Data
public class LeaveRequest {
private String name;
private int day;
private String content;
public LeaveRequest(String name, int day, String content) {
this.name = name;
this.day = day;
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, 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 (leave.getDay() >= numStart && leave.getDay() <= this.numEnd) {
System.out.println("流程成功");
} else if (this.nextHandler != null) {
this.nextHandler.handleLeave(leave);
} else {
System.out.println("流程失败");
}
}
}/**
* 小组长类
*/
public class GroupLeader extends Handler{
public GroupLeader() {
super(0, Handler.NUM_ONE);
}
@Override
protected void handleLeave(LeaveRequest leave) {
System.out.println(leave.getName() + "请假" + leave.getDay() + "天" + leave.getContent() + "请假原因");
System.out.println("小组长审批,同意");
}
}public class Main {
public static void main(String[] args) {
LeaveRequest leave = new LeaveRequest("产假", 5, "回家修养");
//创建各个节点处理
GroupLeader group = new GroupLeader();
Manager manager = new Manager();
GeneralManage generalManage = new GeneralManage();
//设置链
group.setNextHandler(manager);
group.setNextHandler(generalManage);
group.submit(leave);
}
}这个设计模式在Filter链中也有使用,在进行处理的时候先进行前置处理,然后调用责任链的下一个处理器的处理,在结束后进行一开始的后置处理
访问者模式
使用一个访问类,改变了元素类的执行算法
通过这种方式,元素的执行算法可以随着访问者改变而改变,这种类型的设计模式属于行为型模式
根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作
主要讲数据结构与数据操作分离,稳定的数据结构和易变的操作耦合问题
// Element 接口:所有元素必须实现 accept(Visitor)
interface DocumentElement {
void accept(DocumentVisitor visitor);
}
// Visitor 接口:定义对不同元素的操作
interface DocumentVisitor {
void visit(TextElement text);
void visit(ImageElement image);
}// 具体元素:文本
class TextElement implements DocumentElement {
private String content;
public TextElement(String content) {
this.content = content;
}
public String getContent() {
return content;
}
@Override
public void accept(DocumentVisitor visitor) {
visitor.visit(this); // 调用访问者的 visit(TextElement)
}
}
// 具体元素:图片
class ImageElement implements DocumentElement {
private String src;
public ImageElement(String src) {
this.src = src;
}
public String getSrc() {
return src;
}
@Override
public void accept(DocumentVisitor visitor) {
visitor.visit(this); // 调用访问者的 visit(ImageElement)
}
}// 访问者1:导出HTML
class HtmlExportVisitor implements DocumentVisitor {
@Override
public void visit(TextElement text) {
System.out.println("<p>" + text.getContent() + "</p>");
}
@Override
public void visit(ImageElement image) {
System.out.println("<img src=\"" + image.getSrc() + "\"/>");
}
}
// 访问者2:统计字数
class WordCountVisitor implements DocumentVisitor {
private int wordCount = 0;
@Override
public void visit(TextElement text) {
wordCount += text.getContent().split(" ").length;
}
@Override
public void visit(ImageElement image) {
// 图片不参与字数统计
}
public int getWordCount() {
return wordCount;
}
}class Document {
private List<DocumentElement> elements = new ArrayList<>();
public void addElement(DocumentElement element) {
elements.add(element);
}
// 遍历所有元素,接受访问者操作
public void accept(DocumentVisitor visitor) {
for (DocumentElement element : elements) {
element.accept(visitor);
}
}
}public class Client {
public static void main(String[] args) {
Document document = new Document();
document.addElement(new TextElement("Hello World"));
document.addElement(new ImageElement("photo.jpg"));
document.addElement(new TextElement("Visitor Pattern Example"));
// 导出HTML
System.out.println("HTML Export:");
document.accept(new HtmlExportVisitor());
// 统计字数
WordCountVisitor wordCounter = new WordCountVisitor();
document.accept(wordCounter);
System.out.println("Word Count: " + wordCounter.getWordCount());
}
}状态模式
在状态模式中,类的行为是基于它的状态改变的
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类
对象的行为依赖于它的属性,并且可以根据它的状态改变而改变它的相关行为
内容类
public class Context {
private State state;
public Context() {
state = null;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
}状态接口,其中传入Context类
public interface State {
public void operator(Context context);
}实现状态接口
public class StartState implements State {
@Override
public void operator(Context context) {
System.out.println("开启");
context.setState(this);
}
@Override
public String toString() {
return "正在进行...";
}
}public class StopState implements State {
@Override
public void operator(Context context) {
context.setState(this);
}
@Override
public String toString() {
return "已结束...";
}
}调用
public class Main {
public static void main(String[] args) {
Context context = new Context();
State start = new StartState();
start.operator(context);
System.out.println(start.toString());
State stop = new StopState();
stop.operator(context);
System.out.println(stop.toString());
}
}