- 行为型模式, 主要负责算法和对象间责任分配.
- 通过使用对象组合, 行为型模型可以描述一组对象应该如何协作来完成一个整体对象.
责任链
- 使得多个对象都有机会处理请求, 从而避免请求的发送者和接受者之间的耦合关系.
- 将这些对象连成一条链, 并沿着这条链处理该请求, 知道有一个对象处理它位置
- 责任链模式(Chain of Responsibility)是一种请求处理模式, 让多个处理器有机会处理该请求, 知道某个成功为止.
- 责任链模式把多个处理器串成链, 让请求在链上传递.
public class HandlerChain {
// 持有所有的handler
private List<Handler> handlers = new ArrayList<>();
public void addHandler(Handler handler) {
this.handlers.add(handler);
}
public boolean process(Request request) {
// 以此调用每个handler
for (Handler handler : handlers) {
Boolean r = handler.process(request);
// 一旦出现结果, 便返回结果
if (r != null) return r;
}
throw new RuntimeException();
}
}
- handler的添加顺序很重要
public class AHandler implements Handler {
private Handler next;
public void process(Request request) {
if (!canProcess(request)) {
// 手动交给下一个Handler处理:
next.process(request);
} else {
...
}
}
}
-
可以让上一个处理器调用下一个处理器
-
让每个处理器都处理Request的方法称为, 拦截器.
-
目的不是找到某个handler处理掉request, 而是每个handler都做一些工作.
命令
- 将一个请求封装成一个对象, 从而使你可以使用不同的参数, 对客户端的请求进行参数化.
- 对请求排队或者记录请求日志, 以及支持可撤销的操作
- 命令(Command)模式是指: 把请求封装成一个命令, 然后执行这个命令.
这就是命令模式的结构:
┌──────┐ ┌───────┐
│Client│─ ─ ─>│Command│
└──────┘ └───────┘
│ ┌──────────────┐
├─>│ CopyCommand │
│ ├──────────────┤
│ │editor.copy() │─ ┐
│ └──────────────┘
│ │ ┌────────────┐
│ ┌──────────────┐ ─>│ TextEditor │
└─>│ PasteCommand │ │ └────────────┘
├──────────────┤
│editor.paste()│─ ┘
└──────────────┘
解释器
- 给定一个语言, 定义它的文法的一种表示, 并定义一个解释器, 这个解释器使用该表示来解释语言中的句子.
-
解释器模式(Interpreter)是一种针对特定问题设计的解决方法.
-
把正则表达式解析为语法树, 然后再匹配指定的字符串, 就需要一个解析器.
-
当我们使用JDBC时, 执行的SQL语句虽然是字符串, 但最终需要数据库服务器的SQL解释器来把SQL"翻译"成数据库服务器能执行的代码, 这个执行引擎也非常复杂, 但对于使用者来说, 仅仅需要写出SQL字符即可.
public static void main(String[] args) {
log("[{}] start {} at {}", LocalTime.now().withNano(0), "engine", LocalDate.now());
}
static void log (String format, Object... args) {
int len = format.length();
int argIndex = 0;
char last = '\0';
StringBuilder sb = new StringBuilder(len + 20);
for (int i = 0; i < len; i++) {
char now = format.charAt(i);
if (last == '{' && now == '}') {
sb.deleteCharAt(sb.length() - 1);
sb.append(args[argIndex]);
argIndex++;
} else {
sb.append(now);
}
last = now;
}
System.out.println(sb.toString());
}
迭代器
- 提供一种方法顺序访问一个聚合对象中的各个元素, 而又不需要暴露该对象的内部表示
- 迭代器(Iterator).
List<String> list = ...
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
String s = it.next();
}
// 自我定义反向迭代器
public class ReverseArrayCollection<T> implements Iterable<T> {
private T[] array;
@SafeVarargs
public ReverseArrayCollection(T... objs) {
this.array = Arrays.copyOfRange(objs, 0, objs.length);
}
@Override
public Iterator<T> iterator() {
return null;
}
class ReverseIterator implements Iterator<T> {
// 索引位置
private int index;
public ReverseIterator() {
// 初始化的时候, 让索引指向数组的末尾
this.index = ReverseArrayCollection.this.array.length;
}
@Override
public boolean hasNext() {
// 索引>0, 可以继续向下移动
return index > 0;
}
@Override
public T next() {
index--;
return array[index];
}
}
}
中介
- 用一个中介对象来封装一系列的对象交互. 中介者使各个对象不需要显式地相互引用, 从而让耦合松散, 而且可以独立地改变它们之间的交互
- 中介者模式(Mediator), 又称为调停者模式, 目的是把多方会谈, 变成双方会谈, 从而实现多方的松耦合.
public class Main {
public static void main(String[] args) {
new OrderFrame("Hamburger", "Nugget", "Chip", "Coffee");
}
}
/**
* InnerMain
*/
class OrderFrame extends JFrame {
/**
*
*/
private static final long serialVersionUID = 2665832664109930397L;
public OrderFrame(String... names) {
setTitle("Order");
setSize(460, 200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new FlowLayout(
FlowLayout.LEADING, 20, 20
));
c.add(new JLabel("Use Mediator Pattern"));
List<JCheckBox> checkBoxList = addCheckBox(names);
JButton selectAll = addButton("Select All");
JButton selectNone = addButton("Select None");
selectNone.setEnabled(false);
JButton selectInverse = addButton("Inverse Select");
new Mediator(checkBoxList, selectAll, selectNone, selectInverse);
setVisible(true);
}
private List<JCheckBox> addCheckBox(String... names) {
JPanel panel = new JPanel();
panel.add(new JLabel("Menu: "));
List<JCheckBox> list = new ArrayList<>();
for (String name : names) {
JCheckBox checkBox = new JCheckBox(name);
list.add(checkBox);
panel.add(checkBox);
}
getContentPane().add(panel);
return list;
}
private JButton addButton(String label) {
JButton button = new JButton(label);
getContentPane().add(button);
return button;
}
}
public class Mediator {
// 引入UI组件
private List<JCheckBox> checkBoxList;
private JButton selectAll;
private JButton selectNone;
private JButton selectInverse;
public Mediator(List<JCheckBox> checkBoxList, JButton selectAll, JButton selectNone, JButton selectInverse) {
this.checkBoxList = checkBoxList;
this.selectAll = selectAll;
this.selectNone = selectNone;
this.selectInverse = selectInverse;
// 绑定事件
this.checkBoxList.forEach(checkBox -> {
checkBox.addChangeListener(this::onCheckBoxChanged);
});
this.selectAll.addActionListener(this::onSelectAllClicked);
this.selectNone.addActionListener(this::onSelectNoneClicked);
this.selectInverse.addActionListener(this::onSelectInverseClicked);
}
// 当checkbox有变化时
public void onCheckBoxChanged(ChangeEvent event) {
boolean allChecked = true;
boolean allUnchecked = true;
for (JCheckBox checkBox: checkBoxList) {
if (checkBox.isSelected()) {
allUnchecked = false;
} else {
allChecked = false;
}
}
selectAll.setEnabled(!allChecked);
selectNone.setEnabled(!allUnchecked);
}
// 点击select all
public void onSelectAllClicked(ActionEvent event) {
checkBoxList.forEach(checkBox -> checkBox.setSelected(true));
selectAll.setEnabled(false);
selectNone.setEnabled(true);
}
// 当点击select none
public void onSelectNoneClicked(ActionEvent event) {
checkBoxList.forEach(checkBox -> checkBox.setSelected(false));
selectAll.setEnabled(true);
selectNone.setEnabled(false);
}
// 当点击select inverse
public void onSelectInverseClicked(ActionEvent event) {
checkBoxList.forEach(checkBox -> checkBox.setSelected(!checkBox.isSelected()));
onCheckBoxChanged(null);
}
}
-
使用Mediator模式后, 我们可以得到以下好处
- 各个UI组件互不引用, 这样就减少了组件之间的耦合关系
- Mediator用于当一个组件发生状态变化时, 根据当前所有组件的状态决定更新某些组件.
- 如果新增一个UI组件, 我们只需要修改Mediator更新状态的逻辑, 现有的其他UI组件不变化.
-
Mediator模式常用在有众多交互组件的UI上.
-
为了简化UI程序, MVC模式以及MVVM模式都可以看作是Mediator模式的扩展.
-
中介模式就是引入一个中介对象, 把多边关系变成多个双边关系
备忘录
在不破坏封闭性的前提下, 捕获一个对象的内部状态, 并在该对象之外保存这个状态.
-
备忘录模式(Memento): 主要是用于捕获一个对象的内部状态, 以便在将来的某个时刻恢复此状态
-
标准的备忘录有几中角色:
- Memento: 存储的内部状态
- Originator: 创建一个备忘录并设置其状态
- Caretaker: 负责保存备忘录
观察者
定义对象间的一种一对多的依赖关系, 当一个对象的状态发生改变时, 所有依赖它的对象都得到通知并被自动更新
- 观察者模式(Observer)又称为发布-订阅模式(Publish-Subscribe Pub/Sub). 是一种通知机制, 让发送通知的一方(被观察方)和接收通知的一方(观察者)能彼此分离, 互不影响
public class Store {
private List<ProductObserver> observers = new ArrayList<>();
private Map<String, Product> products = new HashMap<>();
// 注册观察者
public void addObsever(ProductObserver observer) {
this.observers.add(observer);
}
// 取消注册
public void removeObserver(ProductObserver observer) {
this.observers.remove(observer);
}
public void addNewProduct(String name, double price) {
Product p = new Product(name, prize);
products.put(p.getName(), p);
// 通知观察者
observers.forEach(o -> o.onPublished(p));
}
public void setProductPrice(String name, double price) {
Product p = products.get(name);
p.setPrice(price);
// 通知观察者
observers.forEach(o -> o.onPriceChanged(p));
}
}
- 可以匿名注册观察者
store.addObserver(new ProductObserver() {
public void onPublised(Product product) {
System.out.println("[Log] on product published: " + product);
}
public void onPriceChanged(Product product) {
System.out.println("[Log] on product price changed: " + product);
}
});
- 也可以把被观察者抽象出接口
public interface ProductObservable {
void addObserver(ProductObserver observer);
void removeObserver(ProductObserver observer);
}
- 也可以用把通知变成一个Event对象, 从而不再有多种方法通知
interface ProductObserver {
void onEvent(ProductEvent event);
}
- 可以异步执行任务
observers.forEach(o -> new Thread() {
@Override
public void run() {
o.onPublished(p);
}
}.start());
状态
允许一个对下个在其内部状态改变时, 改变它的行为. 对象看起来似乎修改了它的类
-
状态模式(State)经常用在带有状态的对象中.
-
可以定一个
enum
就可以表示不同的状态. 但不同的状态需要对应不同的行为. -
状态模式的目的是为了让一搭串的
if...else...
的逻辑拆分到不同的状态类中, 使得将来增加状态比较容易. -
状态模式的核心思想在于状态转换
public class BotContent {
// 默认离线状态
private State state = new DisconnectedState();
public String chat(String input) {
if ("hello".equalsIgnoreCase(input)) {
// 切换到在线状态
state = new ConnectedState();
return state.init();
} else if ("bye".equalsIgnoreCase(input)) {
// 离线状态
state = new DisconnectedState();
return state.init();
}
return state.reply(input);
}
}
策略
策略定义一系列的算法, 把它们一个个封装起来, 并使它们可以相互替换. 本模式主要是算法, 可以独立与使用它的客户而变化.
- 策略模式: Strategy, 是指, 定义一组算法, 并把其封装到一个对象中. 然后在运行的时候, 可以灵活的运行其中某一个算法.
- 流程是确定的, 但是, 某些关键步骤的算法依赖调用方传入的策略.
String[] array = {"apple", "Pear", "Banana", "orange"};
// Arrays.sort(array, String::compareToIgnoreCase);
Arrays.sort(array, String::compareTo);
System.out.println(Arrays.toString(array));
模板方法
定于一个操作中的算法的骨架, 而将一些步骤延迟到子类中, 使得子类可以不改变一个算法的结构, 即可重定义该算法的某些特定步骤.
- 模板方法(template method)是一个比较简单的模式. 它的思想主要是, 定义一个操作的一系列步骤, 对于某些暂时确定不了的步骤, 就留给子类去实现好了, 这样不同的子类就可以定义出不同的步骤.
- 模板方法的核心在于定义一个"骨架".
public abstract class AbstractSetting {
public final String getSetting(String key) {
String value = lookupCache(key);
if (value == null) {
value = readFromDatabase(key);
putIntoCache(key, value);
}
return null;
}
public String readFromDatabase(String key) {
return "value..";
}
protected abstract String lookupCache(String key);
protected abstract void putIntoCache(String key, String value);
}
public class LocalSetting extends AbstractSetting {
private Map<String, String> cache = new HashMap<>();
@Override
protected String lookupCache(String key) {
return cache.get(key);
}
@Override
protected void putIntoCache(String key, String value) {
cache.put(key, value);
}
}
- 模板思想核心: 父类定义骨架, 子类实现某些细节.
- 为了防止子类重写父类的骨架方法, 可以在父类中对骨架方法使用
final
. - 对于子类需要实现的抽象方法, 一般声明为
protected
, 使得这些方法对外部客户端不可见.
访问者
表示一个作用于某对象结构中的各个元素的操作.
它使你可以在不改变各元素的类的前提下, 定义作用这些元素的操作
- 访问者模式(Visitor), 是一种操作一组对象的操作, 目的是不改变对象的定义, 但允许新增不同的访问者, 来定义新的操作.
public class FileStructure {
// 根目录
private File path;
public void handle(Visitor visitor) {
scan(path, visitor);
}
public void scan(File file, Visitor visitor) {
if (file.isDirectory()) {
// 让访问者处理文件夹:
visitor.visitDir(file);
for (File sub : file.listFiles()) {
// 递归处理子文件夹
scan(sub, visitor);
}
} else if (file.isFile()) {
// 让访问者处理文件
visitor.visitFile(file);
}
}
public FileStructure(File path) {
this.path = path;
}
}
public class JavaFileVisitor implements Visitor {
@Override
public void visitDir(File dir) {
System.out.println("Visit dir: " + dir);
}
@Override
public void visitFile(File file) {
if (file.getName().endsWith(".java")) {
System.out.println("Found java file: " + file);
}
}
}
public interface Visitor {
// 访问文件夹
void visitDir(File dir);
// 访问文件
void visitFile(File file);
}
FileStructure fs = new FileStructure(new File("."));
fs.handle(new JavaFileVisitor());
- 访问者模式的核心思想是为了访问比较复杂的数据结构, 不去改变数据结构, 而是把对数据的操作抽象出来
- 在"访问"的过程中以回调形式在访问者中处理操作逻辑
public class App {
public static void main(String[] args) throws IOException {
Files.walkFileTree(Paths.get("."), new MyFileVisitor());
}
}
class MyFileVisitor extends SimpleFileVisitor<Path> {
// 处理文件夹
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
System.out.println("pre visit dir: " + dir);
return FileVisitResult.CONTINUE;
}
// 处理文件
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println("visit file: " + file);
// 返回CONTINUE表示继续访问
return FileVisitResult.CONTINUE;
}
}
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java笔记21 – 设计模式 – 行为型模式 - Python技术站