熊猫儿
发表于 2016-9-11 21:06
所以中介者模式适合的场景就很明确了:当对象之间的交互操作很多且每个对象的行为操作都依赖彼此时,为防止在修改一个对象的行为时,同时涉及修改很多其他对象的行为,可采用中介者模式,来解决紧耦合的问题。UML类图 我们来看看中介者模式的 uml 类图:
http://img.blog.csdn.net/20160831112705100
中介者模式有三个角色:
[*]Mediator:抽象中介者角色,定义了同事对象到中介者对象的接口,可以通过抽象类或者接口的方式实现;
[*]ConcreteMediator:具体中介者角色,继承或者实现了抽象中介者,实现了父类定义的方法,它从具体的同事对象接受消息,向具体同事对象发出命令;
[*]Colleague:抽象同事类角色,定义了同事对象的接口,它只知道中介者而不知道其他的同事对象;
[*]ConcreteColleague:具体同事类角色,继承抽象同事类,每个具体同事类都知道本身在小范围内的行为,而不知道它在大范围内的目的。
根据上面的类图我们写出中介者模式的通用代码:
抽象同事类:
熊猫儿
发表于 2016-9-11 21:06
Colleague.class
public abstract class Colleague { protected Mediator mediator; public void setMediator(Mediator mediator) { this.mediator = mediator; } public abstract void operation();}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
具体同事类:
ConcreteColleagueA.class && ConcreteColleagueB.classpublic class ConcreteColleagueA extends Colleague{ public void notifyColleagueB() { mediator.notifyColleagueB(); } @Override public void operation() { System.out.print("this is ConcreteColleagueA's operation\n"); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
public class ConcreteColleagueB extends Colleague{ public void notifyColleagueA() { mediator.notifyColleagueA(); } @Override public void operation() { System.out.print("this is ConcreteColleagueB's operation\n"); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
抽象中介者角色:
Mediator.classpublic abstract class Mediator { protected Colleague colleagueA; protected Colleague colleagueB; public Mediator(Colleague colleagueA, Colleague colleagueB) { this.colleagueA = colleagueA; this.colleagueB = colleagueB; } public abstract void notifyColleagueA(); public abstract void notifyColleagueB();}
熊猫儿
发表于 2016-9-11 21:07
ConcreteMediator.classpublic class ConcreteMediator extends Mediator{ public ConcreteMediator(Colleague colleagueA, Colleague colleagueB) { super(colleagueA, colleagueB); } @Override public void notifyColleagueA() { if (colleagueA != null) { colleagueA.operation(); } } @Override public void notifyColleagueB() { if (colleagueB != null) { colleagueB.operation(); } }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
测是代码:public class Client { public static void main(String[] args) { Colleague colleagueA = new ConcreteColleagueA(); Colleague colleagueB = new ConcreteColleagueB(); Mediator mediator = new ConcreteMediator(colleagueA, colleagueB); colleagueA.setMediator(mediator); colleagueB.setMediator(mediator); ((ConcreteColleagueA)colleagueA).notifyColleagueB(); ((ConcreteColleagueB)colleagueB).notifyColleagueA(); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
最后结果:this is ConcreteColleagueB's operationthis is ConcreteColleagueA's operation
[*]1
[*]2
两个 Colleague 类成功通过 Mediator 进行了相互作用。上面这个是中介者模式的标准写法,就我自己在项目中实际使用中介者模式来说,有时候将同事子类抽象出一个 Colleague 父类是不太合理的,因为子类之间的业务逻辑的不同,导致他们很难抽象出一些公用方法,所以这时候使用中介者模式,可以省去 Colleague 这个角色,让 Mediator 直接依赖于几个同事子类;同时也可以不定义Mediator接口,把具体的中介者对象实现成为单例,这样同事对象不再持有中介者,而是在需要的时候直接获取中介者对象并调用;中介者也不再持有同事对象,而是在具体处理方法里面去创建,或获取,或从数据传入需要的同事对象。示例与源码 在 Android 源码中也有很多使用中介者模式的例子,比如最突出的就是 Binder 中的 Binder Driver 这个角色,它连接了 Binder client , Binder server 和 ServiceManager,相当于一个中介者,感兴趣的可以去看看我的这篇博客android IPC通信(下)-AIDL。
我这里仍然以 wiki 的 demo 为例,使用 Mediator 来控制 3 个按钮实现 book,view 和 search 的功能:
熊猫儿
发表于 2016-9-11 21:08
ConcreteMediator.classpublic class ConcreteMediator extends Mediator{ public ConcreteMediator(Colleague colleagueA, Colleague colleagueB) { super(colleagueA, colleagueB); } @Override public void notifyColleagueA() { if (colleagueA != null) { colleagueA.operation(); } } @Override public void notifyColleagueB() { if (colleagueB != null) { colleagueB.operation(); } }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
测是代码:public class Client { public static void main(String[] args) { Colleague colleagueA = new ConcreteColleagueA(); Colleague colleagueB = new ConcreteColleagueB(); Mediator mediator = new ConcreteMediator(colleagueA, colleagueB); colleagueA.setMediator(mediator); colleagueB.setMediator(mediator); ((ConcreteColleagueA)colleagueA).notifyColleagueB(); ((ConcreteColleagueB)colleagueB).notifyColleagueA(); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
最后结果:this is ConcreteColleagueB's operationthis is ConcreteColleagueA's operation
[*]1
[*]2
两个 Colleague 类成功通过 Mediator 进行了相互作用。上面这个是中介者模式的标准写法,就我自己在项目中实际使用中介者模式来说,有时候将同事子类抽象出一个 Colleague 父类是不太合理的,因为子类之间的业务逻辑的不同,导致他们很难抽象出一些公用方法,所以这时候使用中介者模式,可以省去 Colleague 这个角色,让 Mediator 直接依赖于几个同事子类;同时也可以不定义Mediator接口,把具体的中介者对象实现成为单例,这样同事对象不再持有中介者,而是在需要的时候直接获取中介者对象并调用;中介者也不再持有同事对象,而是在具体处理方法里面去创建,或获取,或从数据传入需要的同事对象。示例与源码 在 Android 源码中也有很多使用中介者模式的例子,比如最突出的就是 Binder 中的 Binder Driver 这个角色,它连接了 Binder client , Binder server 和 ServiceManager,相当于一个中介者,感兴趣的可以去看看我的这篇博客android IPC通信(下)-AIDL。
我这里仍然以 wiki 的 demo 为例,使用 Mediator 来控制 3 个按钮实现 book,view 和 search 的功能:
熊猫儿
发表于 2016-9-11 21:09
中介者角色:
Mediator.classinterface Mediator { void book(); void view(); void search(); void registerView(BtnView v); void registerSearch(BtnSearch s); void registerBook(BtnBook b); void registerDisplay(LblDisplay d);}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
ParticipantMediator.classclass ParticipantMediator implements Mediator { BtnView btnView; BtnSearch btnSearch; BtnBook btnBook; LblDisplay show; //.... public void registerView(BtnView v) { btnView = v; } public void registerSearch(BtnSearch s) { btnSearch = s; } public void registerBook(BtnBook b) { btnBook = b; } public void registerDisplay(LblDisplay d) { show = d; } public void book() { btnBook.setEnabled(false); btnView.setEnabled(true); btnSearch.setEnabled(true); show.setText("booking..."); } public void view() { btnView.setEnabled(false); btnSearch.setEnabled(true); btnBook.setEnabled(true); show.setText("viewing..."); } public void search() { btnSearch.setEnabled(false); btnView.setEnabled(true); btnBook.setEnabled(true); show.setText("searching..."); }}
熊猫儿
发表于 2016-9-11 21:09
最后测试程序:class MediatorDemo extends JFrame implements ActionListener { Mediator med = new ParticipantMediator(); MediatorDemo() { JPanel p = new JPanel(); p.add(new BtnView(this, med)); p.add(new BtnBook(this, med)); p.add(new BtnSearch(this, med)); getContentPane().add(new LblDisplay(med), "North"); getContentPane().add(p, "South"); setSize(400, 200); setVisible(true); } public void actionPerformed(ActionEvent ae) { Command comd = (Command) ae.getSource(); comd.execute(); } public static void main(String[] args) { new MediatorDemo(); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
用法可能和上面的有些差距,但是思想是一样的,代码也一目了然。总结 在面向对象的变成语言里,一个类必然会与其他类产生依赖关系,如果这种依赖关系如网状般错综复杂,那么必然会影响我们的代码逻辑以及执行效率,适当地使用中介者模式可以对这种依赖关系进行解耦使逻辑结构清晰,但是,如果几个类之间的关系并不复杂,耦合也很少,使用中介者模式反而会使得原本不复杂的逻辑结构变得复杂,所以,我们在决定使用中介者模式之前需要多多考虑,权衡利弊。
优点:
[*]适当的使用中介者模式可以避免同事类之间的过度耦合,使得各同事类之间可以相对独立地使用;
[*]使用中介者模式可以将对象间一对多的关联转变为一对一的关联,使对象间的关系易于理解和维护;
[*]使用中介者模式可以将对象的行为和协作进行抽象,能够比较灵活的处理对象间的相互作用。
缺点:
[*]使用中介者模式需要权衡一下,不能因为同事类少就不适合使用中介者模式,也不能因为同事类多就一定要使用中介者模式,重要的是解耦合,就算是三个类,他们直接的耦合很严密,导致一个类的修改会严重影响到另外两个类,这时候就可以考虑使用中介者,另一方面,类如果很多但是相互都是简单的连接,耦合性低,使用中介者模式就显得不是那么必要了;
[*]随着同事子类的增多和类之间关系的复杂化,中介者会变得越来越庞大,减少可维护性。
源码下载 https://github.com/zhaozepeng/Design-Patterns/tree/master/MediatorPattern引用https://en.wikipedia.org/wiki/Mediator_pattern
http://blog.csdn.net/jason0539/article/details/45216585
熊猫儿
发表于 2016-9-12 14:57
java/android 设计模式学习笔记(19)---状态模式
标签: 设计模式androidjava
2016-09-04 19:14 411人阅读 评论(2) 收藏 举报
http://static.blog.csdn.net/images/category_icon.jpg 分类:
Android(69) http://static.blog.csdn.net/images/arrow_triangle%20_down.jpg Java(24) http://static.blog.csdn.net/images/arrow_triangle%20_down.jpg Android/Java 设计模式(19) http://static.blog.csdn.net/images/arrow_triangle%20_down.jpg
版权声明:转载请标明出处http://blog.csdn.net/self_study,对技术感兴趣的同鞋加群544645972一起交流
目录(?)[+]
这篇博客我们来介绍一下状态模式(State Pattern),也是行为型设计模式之一。状态模式的行为是由状态来决定的,不同的状态下有不同的行为。状态模式和策略模式的结构类图几乎完全一样,但它们的目的、本质却完全不一样。状态模式的行为是平行的、不可替换的,策略模式的行为是彼此独立、可相互替换的。状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类;而策略模式可以想象成是除了继承之外的一种弹性替代方案,如果你使用继承定义了一个类的行为,你将被这个行为困住,甚至要修改它都很难,有了策略模式,你可以通过组合不同的对象来改变行为。状态模式的意图是让一个对象在其内部状态发生改变的时候,其行为也随之改变。
转载请注明出处:http://blog.csdn.net/self_study/article/details/52432486。
PS:对技术感兴趣的同鞋加群544645972一起交流。设计模式总目录 java/android 设计模式学习笔记目录特点 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
状态模式的使用场景:
[*]一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为;
[*]代码中包含大量与状态有关的条件语句,例如,一个操作中含有庞大的多分枝语句(if-else 或者 switch-case),且这些分支依赖于该对象的状态。
状态模式将每一个条件分支放入一个独立的类中,这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化,这样通过多态来去除过多的、重复的 if-else 等分支语句。
UML类图 http://img.blog.csdn.net/20160904190941341
熊猫儿
发表于 2016-9-12 15:00
状态模式的 uml 类图有三个角色:
[*]Context:环境类,定义客户感兴趣的接口,维护一个 State 子类,这个实例定义了对象的当前状态;
[*]State:抽象状态类或者状态接口,定义一个或者一组接口,表示该状态下的行为;
[*]ConcreteStateA、ConcreteStateB:具体状态类,每一个具体的状态类实现抽象的 State 中定义的接口,从而达到不同状态下的不同行为。
据此我们可以写出状态模式的通用代码:
状态接口以及相关子类:
State.class
public interface State { void doSomething();}
[*]1
[*]2
[*]3
[*]1
[*]2
[*]3
ConcreteStateA.class、ConcreteStateB.class、NullState.classpublic class ConcreteStateA implements State { @Override public void doSomething() { System.out.print("this is ConcreteStateA's function\n"); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
public class ConcreteStateB implements State{ @Override public void doSomething() { System.out.print("this is ConcreteStateB's function\n"); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
public class NullState implements State{ @Override public void doSomething() { //do nothing }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
Context类以及测试代码:
Context.classpublic class Context { private State state = new NullState(); void setState(State state) { this.state = state; } void doSomething() { state.doSomething(); } public static void main(String[] args) { Context context = new Context(); context.setState(new ConcreteStateA()); context.doSomething(); context.setState(new ConcreteStateB()); context.doSomething(); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
最后结果:this is ConcreteStateA's functionthis is ConcreteStateB's function
熊猫儿
发表于 2016-9-12 15:01
示例与源码 在 Android 源码中也有很多状态模式的例子,MediaPlayer 和 WifiStateEngine 等,这里我们来简单看看 MediaPlayer 的状态机:
http://img.blog.csdn.net/20160904175013044
椭圆代表 MediaPlayer 对象可能驻留的状态。弧线表示驱动 MediaPlayer 在各个状态之间迁移的播放控制操作。这里有两种类型的弧线。由一个箭头开始的弧代表同步的方法调用,而以双箭头开头的代表的弧线代表异步方法调用。MediaPlayer在这我就不详细介绍了,网上资料很多,感兴趣的可以去查阅一下。
这里再介绍一下状态机,又称为有限状态自动机 (FSM:Finite State Machine),是表示有限多个状态以及在这些状态之间转移和动作的数学模型。状态存储关于过去的信息,它反映从系统开始到现在时刻输入的变化;转移指示状态变更,用必须满足来确使转移发生的条件来描述它;动作是在给定时刻要进行的活动描述,详细的看看这篇博客:有限状态机(FSM)的Java 演示 。
实际 Android 开发过程中,我们一般会去根据实际情况去先构造一个状态图,定义每个状态和每个状态之间切换的事件,类似于上图的 MediaPlayer,然后将该信息录入进入状态机,当目前的状态接收到一个非法的跳转事件时,可以抛出异常,这样就能保证一切按照预先设定好的方向进行。Demo 我们这里仍然以 wiki 上的 demo 为例,来实现一堆字符串的一个大小写间隔打印:
Statelike.classinterface Statelike { void writeName(StateContext context, String name);}
[*]1
[*]2
[*]3
[*]1
[*]2
[*]3
StateLowerCase.class 和 StateMultipleUpperCase.classclass StateLowerCase implements Statelike { @Override public void writeName(final StateContext context, final String name) { System.out.println(name.toLowerCase()); context.setState(new StateMultipleUpperCase()); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
class StateMultipleUpperCase implements Statelike { /** Counter local to this state */ private int count = 0; @Override public void writeName(final StateContext context, final String name) { System.out.println(name.toUpperCase()); /* Change state after StateMultipleUpperCase's writeName() gets invoked twice */ if(++count > 1) { context.setState(new StateLowerCase()); } }}
熊猫儿
发表于 2016-9-12 15:02
StateContext.classclass StateContext { private Statelike myState; StateContext() { setState(new StateLowerCase()); } /** * Setter method for the state. * Normally only called by classes implementing the State interface. * @param newState the new state of this context */ void setState(final Statelike newState) { myState = newState; } public void writeName(final String name) { myState.writeName(this, name); } public static void main(String[] args) { final StateContext sc = new StateContext(); sc.writeName("Monday"); sc.writeName("Tuesday"); sc.writeName("Wednesday"); sc.writeName("Thursday"); sc.writeName("Friday"); sc.writeName("Saturday"); sc.writeName("Sunday"); }}
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
[*]30
[*]31
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]8
[*]9
[*]10
[*]11
[*]12
[*]13
[*]14
[*]15
[*]16
[*]17
[*]18
[*]19
[*]20
[*]21
[*]22
[*]23
[*]24
[*]25
[*]26
[*]27
[*]28
[*]29
[*]30
[*]31
最后结果:mondayTUESDAYWEDNESDAYthursdayFRIDAYSATURDAYsunday
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
[*]1
[*]2
[*]3
[*]4
[*]5
[*]6
[*]7
例子也很简单,一目了然。总结 状态模式的关键点在于不同的状态下对于统一行为有不同的响应,这其实就是一个将 if-else 用多态来实现的一个具体实例。在 if-else 或者 switch-case 形势下根据不同的状态进行判断,如果是状态 A 那么执行方法 A,状态 B 执行方法 B,但这种实现使得逻辑耦合在一起,易于出错不易维护,通过状态模式能够很好的消除这类“丑陋”的逻辑处理,当然并不是任何出现 if-else 的地方都应该通过状态模式重构,模式的运用一定要考虑所处的情景以及你要解决的问题,只有符合特定的场景才建议使用对应的模式。和程序状态机(PSM)不同,状态模式用类代表状态,状态的转换可以由 State 类或者 Context 类控制。
优点:
[*]通过将每个状态封装进一个类,将以后所做的修改局部化;
[*]将所有与一个特定状态相关的行为封装到一个对象中,繁琐的状态判断转换成结构清晰的状态类族,在避免代码膨胀的同时增加可维护性和可扩展性。
缺点当然也很明显,也是绝大部分设计模式的通病,类数目的增多。
源码下载 https://github.com/zhaozepeng/Design-Patterns/tree/master/StatePattern引用https://en.wikipedia.org/wiki/State_pattern
http://blog.csdn.net/jason0539/article/details/45021055
http://blog.csdn.net/shulianghan/article/details/38487967
http://blog.csdn.net/eager7/article/details/8517827