此文章承接上文设计模式里的结构型,如有疑惑,请移步上一篇:https://www.jianshu.com/p/1a2bc93cd929
外观模式:
外观模式就是封装子系统的复杂组成,对外提供一个门面角色,客户端通过门面来操作系统,对内部子系统无知,子系统可以有多个,每个可以独立运行,可以被外部直接调用,对于子系统而言,门面角色也相当于客户端
例如:
public class ActionFace implements IModule{
private IModule action1 = new ModuleA();
private IModule action2 = new ModuleB();
private IModule action3 = new ModuleC();
@Override
public void action() {
action1.action();
action2.action();
action3.action();
}
}
这里定义action1,action2,action3模块,总共有3个模块,使用一个类ActionFace来提供action方法,这样外部可以通过调用该方法来同时调用这3个模块,当然了,这3个模块也可以被单独调用,ActionFace只是相当于一个封装
组合模式:
这个模式一般什么情况下面使用呢,就是整体和单体相似,就像树形结构,举个例子,好比文件夹系统,文件夹和文件相似,构成一个树形结构的文件系统,存在一个root节点,文件夹和文件属性相似,这就可以构成组合
举个例子:
定义一个抽象类:
public abstract class Component {
protected String name;
public void setName(String name) {
this.name = name;
}
}
这个类有2个类组合用于形成树形结构:
public class RootComponent extends Component {
private List list = new ArrayList<>();
public void add(Component left){
list.add(left);
}
}
public class LeftComponent extends Component {
private String leftProperty;
}
下一步就是组合这2个类:
public static void main(String[] args){
RootComponent root = new RootComponent();
Component item = new LeftComponent("left");
Component item2 = new LeftComponent("right");
Component root3 = new RootComponent();
root.add(item);
root.add(item2);
root.add(root3);
}
创建root根类,然后添加子元素或者子节点,这个例子就如文件系统,部分和整体类似,所以可以整合在一起
享元模式
这个模式比较简单,就是在一个集合中拿出对象,如果集合里面没有,那么新建这个对象并放入这个集合里面,然后再给外面使用
定义如下:
public class SharedPool {
private HashMap map = new HashMap<>();
public Object getEntity(T key){
if(map.containsKey(key)) {
return map.get(key);
}else{
Object o = new Object();
map.put(key,o);
return o;
}
}
}
这是一个根据key来查找存贮的值,如果不存在,新建加入Map然后返回该对象,当然了,这个可以定义成单利来存贮,不过请注意及时释放,不然会有内存泄漏哦~~
桥接模式:
这个设计模式目前自己也没有看懂。。。
行为型
责任链模式:
该设计模式个人理解为数据结构里面的单链表,每个元素都可能对客户端进行处理,如果一旦被消费了,那么即刻返回,当然也可能存在没有可以处理的请求
举个栗子:
定义一个抽象类,单链表里面每个元素构成如下:
public abstract class IHandler {
private IHandler handler;
public final void setNextHandler(IHandler handler) {
this.handler = handler;
}
public final IHandler getNextHandler() {
return handler;
}
public final boolean handleRequest(String args) {
if(TextUtils.isEmpty(args)) {
return onRequestHandle(args);
}else{
if(null != getNextHandler()) {
return getNextHandler().handleRequest(args);
}
}
return false;
}
abstract boolean onRequestHandle(String args);
}
public class DutyHandler extends IHandler{
@Override
boolean onRequestHandle(String args) {
//handle request return true
//otherwise return false visit next handle
return false;
}
}
链表里面每个子元素都是DutyHandler,使用setNextHandle保存下一个元素,下面我们编写测试:
public static void main(String[] args){
IHandler topHandler = new DutyHandler();
IHandler nextHandler = new DutyHandler();
topHandler.setNextHandler(nextHandler);
IHandler nextHandler2= new DutyHandler();
nextHandler.setNextHandler(nextHandler2);
topHandler.handleRequest("");
}
这个例子创建的链表是这样的 topHandler -- nextHandler --nextHandler2
发送请求就会依次由头到尾调用handleRequest处理,如果成功,那么处理结束,否则查找下一个handler进行处理这个请求,但不保证一定能有链表元素能够处理
命令模式:
命令模式就是对接口实现体的一个分包装,将接口使用不同类引用并在实现体里面调用引用方法,这样可以将客户端与实现体分离,起到解耦作用,举个例子,假设有一个音乐播放器,有播放,停止,快进,返回等等,我们定义一个实现体:
public class AudioPlayer {
public void play(){
//play
}
public void pause(){
//pause
}
public void stop(){
//stop
}
public void skip(){
//skip
}
}
然后定义我们的客户端:
private ActionCommand pause,play,stop,skip;
private void test(){
AudioPlayer player = new AudioPlayer();
pause = new AudioPause(player);
play = new AudioPlay(player);
stop = new AudioStop(player);
skip = new AudioSkip(player);
pause.execute();
play.execute();
stop.execute();
skip.execute();
}
这时候我们发现直接引用了AudioPlayer这个类型,如果需要添加新的功能,那么要修改这2块代码,产生了较高的耦合,下面我们用命令模式,让AudioPlayer对客户端不可见
- 定义接口:
public interface ActionCommand {
void execute();
}
- 添加实现类:
2.1 播放方法的实现类
public class AudioPlay implements ActionCommand{
private AudioPlayer player;
public AudioPlay(AudioPlayer player) {
this.player = player;
}
@Override
public void execute() {
player.play();
}
}
2.2 暂停方法的实现类
public class AudioPause implements ActionCommand{
private AudioPlayer player;
public AudioPause(AudioPlayer player) {
this.player = player;
}
@Override
public void execute() {
player.pause();
}
}
2.3 停止实现类
public class AudioStop implements ActionCommand{
private AudioPlayer player;
public AudioStop(AudioPlayer player) {
this.player = player;
}
@Override
public void execute() {
player.stop();
}
}
2.4 跳过实现类
public class AudioSkip implements ActionCommand{
private AudioPlayer player;
public AudioSkip(AudioPlayer player) {
this.player = player;
}
@Override
public void execute() {
player.skip();
}
}
- 解耦
private ActionCommand pause,play,stop,skip;
private void test(){
AudioPlayer player = new AudioPlayer();
pause = new AudioPause(player);
play = new AudioPlay(player);
stop = new AudioStop(player);
skip = new AudioSkip(player);
pause.execute();
play.execute();
stop.execute();
skip.execute();
}
使用这样可以看出,最终对AudioPlayer进行不同类型包装,包装之后每个类型都是执行execute让后对应执行AudioPlayer相同方法,这样修改AudioPlayer不会对client产生影响,但是缺点就是定义了过多的接口实现类和指令代码
解释器模式:
感觉没遇到过,不做讨论
迭代模式:
这种设计模式主要讲解关于如何进行数据的迭代查找,用于遍历数组中的元素,设计需要实现Iterable与Iterator接口,其实就是学习这2个接口怎么使用,举例如下:
public class CustomMap implements Iterable{
private E[] array = null;
private int index = 0;
public CustomMap(E[] array) {
this.array = array;
index = 0;
}
@NonNull
@Override
public Iterator iterator() {
return new CustomIterator();
}
private class CustomIterator implements Iterator{
@Override
public boolean hasNext() {
return index < array.length;
}
@Override
public E next() {
try {
return array[index];
}finally {
index ++;
}
}
}
}
编写测试方法:
public static void main(String[] args){
Integer[] result = new Integer[]{1,2,5,9,77,51};
CustomMap map = new CustomMap<>(result);
for (Integer i : map) {
System.out.println(String.valueOf(i));
}
}
上面的例子就是对一个数组封装然后实现遍历接口,这样就可以用for来迭代遍历。
中介者模式
该设计模式使用情况比较少,一般用于一个类影响多个类的情况,这种情况下,可能随便一个类都会影响其他多个类,这时候采取一个中介来控制其他类型,用于在一个类改变之后通过中介引用其他类来控制其他类变化
举个例子:假如有一个College类,有5个实例分别是abcde,当a改变的时候bce改变,当b改变的时候ace改变,当d改变的时候e改变,其他不变,那么我们可以这样做:
public class College {
int value;
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
public abstract class IAnency {
College collegea,collegeb,collegec,colleged,collegee;
public IAnency(College collegea, College collegeb, College collegec, College colleged, College collegee) {
this.collegea = collegea;
this.collegeb = collegeb;
this.collegec = collegec;
this.colleged = colleged;
this.collegee = collegee;
}
abstract void setAnency(College target,College... others);
}
定义抽象类,添加抽象方法setAnency,然后定义实现类,第一个参数是改变的成员,后面可变数组是真正需要因第一个参数改变而改变的成员变量
备忘录模式
备忘录模式就是对原对象存储当前节点的状态,用于在以后起到恢复,这个设计模式有点像创建型里面的原型模式,但是原型模式是拷贝对象,这里的设计模式是对某个对象创建状态存储类,然后在合适的时候取出该对象然后执行覆盖恢复
举例:
假设有一个SnapEntity类,里面有statue变量,在某个时刻需要对这个类备份,用于以后需要的时候恢复:
public interface ISnap {
//empty interface
}
public class SnapEntity {
private int statue;
public ISnap createEntity(){
return new SnapShot(this.statue);
}
public void restoreSnapEntity(ISnap snapShot){
statue = ((SnapShot)snapShot).statue;
}
public void setStatue(int statue) {
this.statue = statue;
}
public int getStatue() {
return statue;
}
static class SnapShot implements ISnap{
private int statue;
public SnapShot(int statue) {
this.statue = statue;
}
public int getStatue() {
return statue;
}
}
}
这里定义一个空接口用于恢复的时候强转恢复里面的数据,这样的好处就是外部不能直接访问备份文件,之后在执行变量恢复方法的时候才能访问
下面我们创建一个类来保存备份数据:
public class CareTaker {
private ISnap snapShot;
public void setSnapShot(ISnap snapShot) {
this.snapShot = snapShot;
}
public ISnap getSnapShot() {
return snapShot;
}
}
创建测试方法:
public static void main(String[] args){
SnapEntity entity = new SnapEntity();
entity.setStatue(3);
CareTaker taker = new CareTaker();
taker.setSnapShot(entity.createEntity());
entity.setStatue(7);
entity.restoreSnapEntity(taker.getSnapShot());
System.out.print(String.valueOf(entity.getStatue()));
}
这是一个将之前保存的数据3保存然后再修改之后进行恢复的测试,这就是备忘录模式,当然了,实际情况下一个类型可能有很多变量,我们可以按需来设计或者进行备份,然后再设计一个享元模式的缓存池或者存储。
观察者模式:
这种设计模式都已经用惯了,不多介绍,嘿嘿~
状态模式:
这种设计模式就是对一个行为有不同的实现类来处理,通过不同case来产生接口实现类,每个实现类有特点的实现机制,这就好比switch case语句,这里举个例子:
定义一个接口:
public interface IStatueHandler {
void handleStatue(int args);
}
接口有3个实现类,A,B,C,这3个实现类实现不同方法,然后编写测试方法:
public void handleStatue(int what){
IStatueHandler handler = null;
if(0 < what && what < 11) {
handler = new StatueHandlerA();
}else if(what < 51){
handler = new StatueHandlerB();
}else{
handler = new StatueHandlerC();
}
handler.handleStatue(what);
}
这就是一个状态模式的简单例子,其实就是一个接口不同实现,然后case不同情况进行处理,和下面将要提到的策略模式一样。
策略模式:
该设计模式很像状态模式,同样定义公共接口,然后每个接口有不同的实现策略,并且有且只有一个策略(实现类)可以处理请求,这些策略(实现类)可以被及时替换,耦合性低,这里不再介绍。
模板方法模式:
这种设计模式就是定义抽象类,然后提供抽象方法,在实现具体方法里面提供核心抽象方法由子类实现,这里不再举例