目录
1、模板方法模式
基本介绍
1)模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
2)简单说,模板方法模式 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤
3)这种类型的设计模式属于行为型模式。
主要解决:一些方法通用,却在每一个子类都重新写了这一方法。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
例如:
1、创建一个抽象类,它的模板方法被设置为 final。
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//模板
public final void play(){
//初始化游戏
initialize();
//开始游戏
startPlay();
//结束游戏
endPlay();
}
}
2、创建扩展了上述类的实体类。
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
3、使用者
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
game = new Football();
game.play();
}
}
模板方法模式的钩子方法
在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。
比如,我们希望制作纯豆浆,不添加任何的配料,请使用钩子方法对模板方法进行改造
//抽象类,表示豆浆
public abstract class SoyaMilk {
//模板方法, make , 模板方法可以做成 final , 不让子类去覆盖.
final void make() {
select();
if(customerWantCondiments()) {
addCondiments();
}
soak();
beat();
}
//选材料
void select() {
System.out.println("第一步:选择好的新鲜黄豆 ");
}
//添加不同的配料, 抽象方法, 子类具体实现
abstract void addCondiments();
//浸泡
void soak() {
System.out.println("第三步, 黄豆和配料开始浸泡, 需要 3 小时 ");
}
void beat() {
System.out.println("第四步:黄豆和配料放到豆浆机去打碎 ");
}
//钩子方法,决定是否需要添加配料
boolean customerWantCondiments() {
return true;
}
}
模板方法模式在 Spring 框架应用的源码分析
类图:
2、命令模式
命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
意图:将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
主要解决:在软件系统中,行为请求者与行为实现者通常是一种紧耦合的关系,但某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时,这种无法抵御变化的紧耦合的设计就不太合适。
使用场景:认为是命令的地方都可以使用命令模式,比如: 1、GUI 中每一个按钮都是一条命令。 2、模拟 CMD。
关键代码:定义三个角色:1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口
1、创建command接口:
public interface ICommand {
void execute();
}
2、具体的命令实现类
public class CommandA implements ICommand{
private Receiver receiver;
public CommandA(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
System.out.println("CommandA 执行 .....");
receiver.execute();
}
}
public class CommandB implements ICommand{
private Receiver receiver;
public CommandB(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
System.out.println("CommandB execute ...");
receiver.execute();
}
}
3、Receiver:执行命令的对象,具体怎么执行命令
public class Receiver {
public void execute(){
System.out.println("Receiver 执行命令");
}
}
4、Invoker:创建命令入口,执行命令
public class Invoker {
private ICommand CommandA;
private ICommand CommandB;
public Invoker(ICommand commandA, ICommand commandB) {
CommandA = commandA;
CommandB = commandB;
}
//执行命令A
public void orderA(){
CommandA.execute();
}
//执行命令B
public void orderB(){
CommandB.execute();
}
}
5、使用者
public static void main(String[] args) {
Receiver receiver = new Receiver();
Invoker invoker = new Invoker(new CommandA(receiver), new CommandB(receiver));
invoker.orderA();
invoker.orderB();
}
Spring 框架的 JdbcTemplate 就使用到了命令模式
代码分析
- StatementCallback 接口 ,类似命令接口(Command)
- class QueryStatementCallback implements StatementCallback,SqlProvider , 匿名内部类, 实现了命令接口, 同时也充当命令接收者
- 命令调用者Invoker是 JdbcTemplate , 其中 execute(StatementCallback action)方法中,调用 action.doInStatement 方法. 不同的实现 StatementCallback接口的对象,对应不同的doInStatemnt 实现逻辑
- 另外实现 StatementCallback 命令接口的子类还有 QueryStatementCallback、
3、访问者模式
1)访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
2)主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题
3)访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口
4)访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决
1、Element 定义一个 accept 方法,接收一个访问者对象
public interface ComputerPart {
void accept(ComputerPartVisitor computerPartVisitor);
}
2、ConcreteElement 为具体元素,实现了 accept 方法
public class Computer implements ComputerPart{
ComputerPart[] parts;
public Computer() {
this.parts = new ComputerPart[]{new Mouse(),new Keyboard(),new Monitor()};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
public class Keyboard implements ComputerPart{
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
3、Visitor 是抽象访问者,为该对象结构中的 ConcreteElement 的每一个类声明一个 visit 操作
public interface ComputerPartVisitor {
void visit(Computer computer);
void visit(Mouse mouse);
void visit(Keyboard keyboard);
void visit(Monitor monitor);
}
4、ConcreteVisitor :是一个具体的访问值 实现每个有 Visitor 声明的操作,是每个操作实现的部分.
public class ComputerPartDisplayVisitor implements ComputerPartVisitor{
@Override
public void visit(Computer computer) {
System.out.println("展示 computer");
}
@Override
public void visit(Mouse mouse) {
System.out.println("展示鼠标");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("展示键盘");
}
@Override
public void visit(Monitor monitor) {
System.out.println("展示显示器");
}
}
5、使用者
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
4、迭代器模式
这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。
主要解决:不同的方式来遍历整个整合对象。
何时使用:遍历一个聚合对象。
如何解决:把在元素之间游走的责任交给迭代器,而不是聚合对象。
关键代码:定义接口:hasNext, next。
应用实例:JAVA 中的 iterator。
使用场景: 1、访问一个聚合对象的内容而无须暴露它的内部表示。 2、需要为聚合对象提供多种遍历方式。 3、为遍历不同的聚合结构提供一个统一的接口。
1、Iterator 接口
public interface Iterator {
boolean hasNext();
Object next();
}
2、返回迭代器的 Container 接口
public interface Container {
Iterator getIterator();
}
3、实现了 Container 接口的实体类将负责实现 Iterator 接口。
public class NameRepository implements Container{
public String[] names={"robert","john","julie","lora"};
@Override
public Iterator getIterator() {
return new NameIterator();
}
private class NameIterator implements Iterator{
int index;
@Override
public boolean hasNext() {
if (index<names.length){
return true;
}
return false;
}
@Override
public Object next() {
if (this.hasNext()){
return names[index++];
}
return null;
}
}
}
4、使用
public static void main(String[] args) {
NameRepository nameRepository=new NameRepository();
Iterator iterator = nameRepository.getIterator();
while(iterator.hasNext()){
String name = (String)iterator.next();
System.out.println("Name : " + name);
}
}
5、观察者模式
应用场景:有些业务需要不断的被维护,修改。如果不断的去修改这个方法,可能会造成业务逻辑出错
破坏了单一职责原则,耦合了很多附属性的代码。
破坏了开闭原则(不修改代码的情况下进行扩展),比如:我创建订单的时候,还要发微信消息,肯定要修改代码来扩展功能,又或者我要修改发短信的逻辑的时候,又要动这个方法。
优化:把2,3,4拆出来,分别包到一个类里,然后类似的用一个for循环一个一个的去执行。就是观察者模式
例子:
public class OrderEvent extends ApplicationEvent {
Long id;
public OrderEvent(Object source,Long id) {
super(source);
this.id = id;
}
}
// 发邮件的逻辑放到一个类里
@Component
public class EmailListener implements ApplicationListener<OrderEvent> {
@Override
public void onApplicationEvent(OrderEvent orderEvent) {
System.out.println("发邮件: " + orderEvent.id);
}
}
// 发短信的逻辑放到一个类里
@Component
public class SmsListener implements ApplicationListener<OrderEvent> {
@Override
public void onApplicationEvent(OrderEvent orderEvent) {
System.out.println("发送短信的逻辑。" + orderEvent.id);
}
}
@Service
public class DeviceBusinessPurposeServiceImpl extends ServiceImpl<DeviceBusinessPurposeMapper, DeviceBusinessPurpose> implements DeviceService {
@Autowired
private ApplicationContext applicationContext;
@Override
public void createOrder() {
// 创建订单
Long id = 1L;
System.out.println("创建订单");
// 发布订单相关事件(Spring里有很多事件,指定要发布的事件是OrderEvent的事件)
// 循环调用类里的业务逻辑
applicationContext.publishEvent(new OrderEvent(applicationContext, id));
}
}
ps:这里的Event和Listener ,直接用的Spring提供的。也可以自己写