引用代理对象的方式来访问目标对象,简单点说,就是在调用某个对象时加了一层,然后你可以在这一层做些手脚,比如权限控制,或者附加操作等。
代码示例
Java代码
/* 抽象对象 */
public interface FetchGoods {
public void fetchShoes();
}
/* 真实对象 */
public class Custom implements FetchGoods{
@Override public void fetchShoes() { System.out.println("拿货"); }
}
/* 代理对象 */
public class Agent implements FetchGoods{
@Override public void fetchShoes() {
Custom custom = new Custom();
custom.fetchShoes();
this.callCustom();
}
public void callCustom() { System.out.println("通知顾客过来取件!"); }
}
/* 客户端调用 */
public class Client {
public static void main(String[] args) {
Agent agent = new Agent();
agent.fetchShoes();
}
}
输出结果:
定义一系列的算法,把每个算法封装起来,并使得他们可以相互替换,让算法独立于使用它的客户而变化。 一般用来替换if-else,个人感觉是面向过程与面向对象思想的过渡。
代码示例:(面向过程与面向对象的简易计算器)
面向过程简易计算器
Java代码
public class Calculator {
public static void main(String[] args) {
System.out.println("计算:1 + 1 = " + compute("+", 1, 1));
System.out.println("计算:1 - 1 = " + compute("-", 1, 1));
System.out.println("计算:1 * 1 = " + compute("*", 1, 1));
System.out.println("计算:1 ? 1 = " + compute("/", 1, 1));
}
public static float compute(String operator, int first, int second) {
switch (operator) {
case "+": return first + second;
case "-": return first - second;
case "*": return first * second;
case "/": return first / second;
default: return 0.0f;
}
}
}
面向对象(策略模式)简易计算器
Java代码
/* 抽象策略类 */
public interface Compute {
String compute(int first, int second);
}
/* 具体策略类 */
public class Add implements Compute{
@Override public String compute(int first, int second) {
return "输出结果:" + first + " + " + second + " = " + (first + second);
}
}
public class Sub implements Compute{ /* ... */ }
public class Mul implements Compute{ /* ... */ }
public class Div implements Compute{ /* ... */ }
/* 上下文环境类 */
public class Context {
private Compute compute;
public Context() { compute = new Add(); }
public void setCompute(Compute compute) { this.compute = compute; }
public void calc(int first, int second) {
System.out.println(compute.compute(first, second));
}
}
/* 客户端调用 */
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setCompute(new Add());
context.calc(1,2);
context.setCompute(new Sub());
context.calc(3,4);
context.setCompute(new Mul());
context.calc(5,6);
context.setCompute(new Div());
context.calc(7,8);
}
}
输出结果:
定义对象见的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并且自动更新。
当对象间存在一对多关系的时候,使用观察者模式,当一个对象(被观察者)被修改时,会自动通知它的依赖对象们(观察者)。
这个模式基本都应该用过和听说过,关于概念就不多解释了,有兴趣看原文去~
代码示例:
Java代码
/* 抽象观察者 —— 昆虫类 */
public interface Insect {
void work();
void unWork();
}
/* 具体观察者 —— 蜜蜂类 */
public class Bee implements Insect{
private int bId; //蜜蜂编号
public Bee(int bId) { this.bId = bId; }
@Override public void work() { System.out.println("蜜蜂"+ bId + "采蜜"); }
@Override public void unWork() { System.out.println("蜜蜂"+ bId + "回巢"); }
}
/* 抽象被观察者(注册,移除,通知观察者) —— 植物类 */
public interface Plant {
public void registerInsect(Insect insect);
public void unregisterInsect(Insect insect);
public void notifyInsect(boolean isOpen);
}
/* 具体被观察者(定义一个集合存储观察者,实现相关方法) —— 花朵类 */
public class Flower implements Plant {
private boolean state;
private List<Insect> insects = new ArrayList<>();
public boolean isState() { return state; }
@Override public void registerInsect(Insect insect) { insects.add(insect); }
@Override public void unregisterInsect(Insect insect) { insects.remove(insect); }
@Override public void notifyInsect(boolean isOpen) {
state = isOpen;
if (state) {
System.out.println("花开");
for (Insect insect : insects) { insect.work(); }
} else {
System.out.println("花闭");
for (Insect insect : insects) { insect.unWork(); }
}
}
}
/* 客户端调用 */
public class Client {
public static void main(String[] args) {
//创建被观察者
Plant flower = new Flower();
//创建三个观察者
Insect bee1 = new Bee(1);
Insect bee2 = new Bee(2);
Insect bee3 = new Bee(3);
//注册观察者
flower.registerInsect(bee1);
flower.registerInsect(bee2);
flower.registerInsect(bee3);
//改变被观察者状态,先开后合
flower.notifyInsect(true);
System.out.println("=== 太阳从东边到西边... ===");
flower.notifyInsect(false);
//最后解除注册
flower.unregisterInsect(bee1);
flower.unregisterInsect(bee2);
flower.unregisterInsect(bee3);
}
}
输出结果:
观察者模式的推与拉
推方式
被观察者对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是被观察者对象的全部或部分数据。(上面的例子就是推方式)
拉方式
被观察者对象再通知观察者时,只传递少量信息。如果观察者需要更详细的信息,可以主动到被观察者中获取,相当于观察者从被观察者中拉取数据。一般的套路是:**把主题对象自身通过update()方法传递给观察者,然后观察者在需要获取的时候,通过这个引用来获取**。
代码示例:
微信订阅了某个公众号,当有更新的时候会推送提醒,收到提醒后,我们需要进入公众号然后点击对应信息查看详细内容。
Java代码
/* 抽象观察者 —— 用户 */
public interface User {
public void update(OfficialAccount account);
}
/* 具体观察者 —— Android读者 */
public class AndroidDev implements User {
@Override public void update(OfficialAccount account) {
System.out.println("读者查看公众号更新信息:" + ((CoderPig)account).getMsg());
}
}
/* 抽象被观察者 —— 公众号 */
public abstract class OfficialAccount {
private List<User> userList = new ArrayList<>();
public void registerUser(User user) { userList.add(user); }
public void unregisterUser(User user) { userList.remove(user); }
public void notifyUse() {
for (User user: userList) {
user.update(this);
}
}
}
/* 具体被观察者 —— CoderPig公众号 */
public class CoderPig extends OfficialAccount {
private String msg; //更新的文章
public String getMsg() { return msg; }
public void update(String msg) {
this.msg = msg;
System.out.println("公众号更新了文章:" + msg);
this.notifyUse(); //通知用户有更新
}
}
/* 客户端调用 */
public class Client {
public static void main(String[] args) {
OfficialAccount account = new CoderPig();
User user = new AndroidDev();
account.registerUser(user);
((CoderPig)account).update("《观察者模式》");
account.unregisterUser(user);
}
}
输出结果:
Java中对观察者模式的支持(在Java.util中)
口诀:被观察者实现继承Observable,观察者实现Observer接口,然后有个很关键的地方:当通知变化的时候,需要调用setChange()方法!!!!不用自己另外去写抽象观察者或抽象被观察者类,直接继承就能玩了,另外有一点要注意的是:Java内置的观察者模式通知多个观察者的顺序不是固定的,如果对通知顺序有所依赖的话,还是得自己实现观察者模式!
代码示例:
Java代码
/* 具体观察者 */
public class AndroidDev implements Observer{
@Override public void update(Observable o, Object object) {
System.out.println("收到公众号更新信息:" + object);
}
}
/* 具体被观察者 */
public class CoderPig extends Observable {
private String msg;
public String getMsg() { return msg; }
public void update(String msg) {
this.msg = msg;
System.out.println("公众号更新了文章:" + msg);
this.setChanged(); //这句话必不可少,通知改变
this.notifyObservers(this.msg); //这里用推的方式
}
}
/* 客户端调用 */
public class Client {
public static void main(String[] args) {
CoderPig coderPig = new CoderPig();
AndroidDev dev = new AndroidDev();
coderPig.addObserver(dev);
coderPig.update("Java中对观察者模式的支持~");
coderPig.deleteObserver(dev);
}
}
输出结果:
提供一种方法顺序访问一个容器(聚合)对象中各个元素,而又不暴露该对象的内部表示。
从上面的定义可以知道,这个模式的使用场景:容器对象中的元素迭代访问
四个角色
UML类图
代码示例:
Java代码
/* 集合中的元素 */
public class Song {
private String name;
private String singer;
public Song(String name, String singer) {
this.name = name;
this.singer = singer;
}
/* getter和setter方法 */
@Override public String toString() {
return "【歌名】" + name + " - " + singer;
}
}
/* 迭代器角色,第一项,下一个,判断是否能下一个,获取当前项。 */
public interface Iterator {
Song first();
Song next();
boolean hashNext();
Song currentItem();
}
/* 抽象容器,定义一个生成迭代器的方法 */
interface SongList {
Iterator getIterator();
}
/* 具体容器,继承抽象容器,并定义一个具体迭代器内部类 */
public class MyStoryList implements SongList{
private List<Song> list = new ArrayList<>();
public MyStoryList(List<Song> list) {
this.list = list;
}
@Override public Iterator getIterator() {
return new SongListIterator();
}
private class SongListIterator implements Iterator {
private int cursor;
@Override public Song first() {
cursor = 0;
return list.get(cursor);
}
@Override public Song next() {
Song song = null;
cursor++;
if(hashNext()) {
song = list.get(cursor);
}
return song;
}
@Override public boolean hashNext() {
return !(cursor == list.size());
}
@Override public Song currentItem() {
return list.get(cursor);
}
}
}
/* 客户端调用 */
public class Client {
public static void main(String[] args) {
List<Song> list = new ArrayList<>();
list.add(new Song("空白格","杨宗纬"));
list.add(new Song("那时候的我","刘惜君"));
list.add(new Song("黑泽明","陈奕迅"));
list.add(new Song("今天只做一件事","陈奕迅"));
list.add(new Song("童话镇","陈一发儿"));
MyStoryList songList = new MyStoryList(list);
Iterator iterator = songList.getIterator();
while (iterator.hashNext()) {
System.out.println(iterator.currentItem().toString());
iterator.next();
}
}
}
输出结果:
PS:由于容器与迭代器的关系太密切了,所以大多数语言在实现容器的时候都给提供了迭代器,并且这些语言提供的容器和迭代器在绝大多数情况下就可以满足我们的需要,所以现在需要我们自己去实践迭代器模式的场景还是比较少见的,我们只需要使用语言中已有的容器和迭代器就可以了。
使用场景:行为请求者与行为实现者的解耦
定义:将一个请求封装成一个对象,从而可用不同的请求对客户端参数化,对请求排队或记录请求日志,以及支持可撤销的操作。
代码示例:
Java代码
/* 元素对象 */
public class Story {
private String sName;
private String sUrl;
public Story(String sName, String sUrl) {
this.sName = sName;
this.sUrl = sUrl;
}
/*getter和setter方法*/
}
/* 命令执行者 */
public class StoryPlayer {
private int cursor = 0; //当前播放项
private int pauseCursor = -1; //暂停播放项
private List<Story> playList = new ArrayList<>(); //播放列表
public void setPlayList(List<Story> list) {
this.playList = list;
cursor = 0;
System.out.println("更新播放列表...");
}
public void play() { /* 播放 */ }
public void play(int cursor) { /* 根据游标播放 */ }
public void next() { /* 下一首 */ }
public void pre() { /* 上一首 */ }
public void pause() { /* 暂停 */ }
}
/* 抽象命令接口 */
public interface Command { void execute(); }
/* 具体命令类 */
public class SetListCommand implements Command {
private StoryPlayer mPlayer;
private List<Story> mList = new ArrayList<>();
public SetListCommand(StoryPlayer mPlayer) { this.mPlayer = mPlayer; }
@Override public void execute() { mPlayer.setPlayList(mList); }
public void setPlayList(List<Story> list) { this.mList = list; }
}
public class PlayCommand implements Command {
private StoryPlayer mPlayer;
public PlayCommand(StoryPlayer mPlayer) { this.mPlayer = mPlayer; }
@Override public void execute() { mPlayer.play(); }
}
public class PlayCommand implements Command { /* ... */ }
public class PauseCommand implements Command { /* ... */ }
public class NextCommand implements Command { /* ... */ }
public class PreCommand implements Command { /* ... */ }
/* 请求者类,调用命令对象执行具体操作 */
public class Invoker {
private SetListCommand setListCommand;
private PlayCommand playCommand;
private PauseCommand pauseCommand;
private NextCommand nextCommand;
private PreCommand preCommand;
public void setSetListCommand(SetListCommand setListCommand) {
this.setListCommand = setListCommand;
}
public void setPlayCommand(PlayCommand playCommand) {
this.playCommand = playCommand;
}
public void setPauseCommand(PauseCommand pauseCommand) {
this.pauseCommand = pauseCommand;
}
public void setNextCommand(NextCommand nextCommand) {
this.nextCommand = nextCommand;
}
public void setPreCommand(PreCommand preCommand) {
this.preCommand = preCommand;
}
/* 设置播放列表 */
public void setPlayList(List<Story> list) {
setListCommand.setPlayList(list);
setListCommand.execute();
}
public void play() { playCommand.execute(); } /* 播放 */
public void pause() { pauseCommand.execute(); } /* 暂停 */
public void next() { nextCommand.execute(); } /* 下一首 */
public void pre() { preCommand.execute(); } /* 上一首 */
}
/* 客户端调用 */
public class Client {
public static void main(String[] args) {
//实例化播放列表
List<Story> mList = new ArrayList<>();
mList.add(new Story("白雪公主",""));
mList.add(new Story("青蛙的愿望",""));
mList.add(new Story("驴和妈",""));
mList.add(new Story("小青蛙的烦恼",""));
mList.add(new Story("三字经",""));
//实例化接收者
StoryPlayer mPlayer = new StoryPlayer();
//实例化命令对象
Command setListCommand = new SetListCommand(mPlayer);
Command playCommand = new PlayCommand(mPlayer);
Command pauseCommand = new PauseCommand(mPlayer);
Command nextCommand = new NextCommand(mPlayer);
Command preCommand = new PreCommand(mPlayer);
//实例化请求者
Invoker invoker = new Invoker();
invoker.setSetListCommand((SetListCommand) setListCommand);
invoker.setPlayList(mList);
invoker.setPlayCommand((PlayCommand) playCommand);
invoker.setPauseCommand((PauseCommand) pauseCommand);
invoker.setNextCommand((NextCommand) nextCommand);
invoker.setPreCommand((PreCommand) preCommand);
//测试调用
invoker.play();
invoker.next();
invoker.next();
invoker.next();
invoker.next();
invoker.next();
invoker.pause();
invoker.play();
}
}
输出结果:未完待续。。。
如果想学习Java工程化、高性能及分布式、深入浅出。性能调优、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级架构进阶群:180705916,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家
网友评论