知识大全 设计模式分解java(6)

Posted 状态

篇首语:盛年不重来,一日难再晨,及时当勉励,岁月不待人。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 设计模式分解java(6)相关的知识,希望对你有一定的参考价值。

  /** */

  行为模式 Command

  Command模式是最让我疑惑的一个模式 我在阅读了很多代码后

  才感觉隐约掌握其大概原理 我认为理解设计模式最主要是掌握起原理构造

  这样才对自己实际编程有指导作用 Command模式实际上不是个很具体

  规定很多的模式 正是这个灵活性 让人有些confuse

  Command定义

  不少Command模式的代码都是针对图形界面的 它实际就是菜单命令

  我们在一个下拉菜单选择一个命令时 然后会执行一些动作

  将这些命令封装成在一个类中 然后用户(调用者)再对这个类进行操作 这就是Command模式

  换句话说 本来用户(调用者)是直接调用这些命令的 如菜单上打开文档(调用者)

  就直接指向打开文档的代码 使用Command模式 就是在这两者之间增加一个中间者

  将这种直接关系拗断 同时两者之间都隔离 基本没有关系了

  显然这样做的好处是符合封装的特性 降低耦合度

  Command是将对行为进行封装的典型模式

  Factory是将创建进行封装的模式

  从Command模式 我也发现设计模式一个 通病 :好象喜欢将简单的问题复杂化

  喜欢在不同类中增加第三者 当然这样做有利于代码的健壮性 可维护性 还有复用性

  如何使用?

  具体的Command模式代码各式各样 因为如何封装命令 不同系统 有不同的做法

  下面事例是将命令封装在一个Collection的List中 任何对象一旦加入List中 实际上装入了一个封闭的黑盒中

  对象的特性消失了 只有取出时 才有可能模糊的分辨出:

  典型的Command模式需要有一个接口 接口中有一个统一的方法 这就是 将命令/请求封装为对象 :

  public interface Command

  public abstract void execute ( );

  

  具体不同命令/请求代码是实现接口Command 下面有三个具体命令

  public class Engineer implements Command

  public void execute( )

  //do Engineer s mand

  

  

  public class Programmer implements Command

  public void execute( )

  //do programmer s mand

  

  

  public class Politician implements Command

  public void execute( )

  //do Politician s mand

  

  

  按照通常做法 我们就可以直接调用这三个Command 但是使用Command模式

  我们要将他们封装起来 扔到黑盒子List里去:

  public class producer

  public static List produceRequests()

  List queue = new ArrayList();

  queue add( new DomesticEngineer() );

  queue add( new Politician() );

  queue add( new Programmer() );

  return queue;

  

  

  这三个命令进入List中后 已经失去了其外表特征 以后再取出

  也可能无法分辨出谁是Engineer 谁是Programmer了 看下面如何调用Command模式:

  public class TestCommand

  public static void main(String[] args)

  List queue = Producer produceRequests();

  for (Iterator it = erator(); it hasNext(); )

  //取出List中东东 其他特征都不能确定 只能保证一个特征是 %正确

  // 他们至少是接口Command的 儿子 所以强制转换类型为接口Command

  ((Command)it next()) execute();

  

  

  由此可见 调用者基本只和接口打交道 不合具体实现交互 这也体现了一个原则

  面向接口编程 这样 以后增加第四个具体命令时 就不必修改调用者TestCommand中的代码了

  理解了上面的代码的核心原理 在使用中 就应该各人有自己方法了 特别是在如何分离调用者和具体命令上

  有很多实现方法 上面的代码是使用 从List过一遍 的做法 这种做法只是为了演示

  使用Command模式的一个好理由还因为它能实现Undo功能

  每个具体命令都可以记住它刚刚执行的动作 并且在需要时恢复

  Command模式在界面设计中应用广泛 Java的Swing中菜单命令都是使用Command模式

  /** */

  行为模式 State

  State的定义: 不同的状态 不同的行为;或者说 每个状态有着相应的行为

  何时使用?

  State模式在实际使用中比较多 适合 状态的切换 因为我们经常会使用If elseif else 进行状态切换

  如果针对状态的这样判断切换反复出现 我们就要联想到是否可以采取State模式了

  不只是根据状态 也有根据属性 如果某个对象的属性不同 对象的行为就不一样

  这点在数据库系统中出现频率比较高 我们经常会在一个数据表的尾部

  加上property属性含义的字段 用以标识记录中一些特殊性质的记录

  这种属性的改变(切换)又是随时可能发生的 就有可能要使用State

  是否使用?

  在实际使用 类似开关一样的状态切换是很多的 但有时并不是那么明显 取决于你的经验和对系统的理解深度

  这里要阐述的是 开关切换状态 和 一般的状态判断 是有一些区别的

  一般的状态判断 也是有 if elseif结构 例如:

  if (which== ) state= hello ;

  else if (which== ) state= hi ;

  else if (which== ) state= bye ;

  这是一个 一般的状态判断 state值的不同是根据which变量来决定的 which和state没有关系 如果改成:

  if (state euqals( bye )) state= hello ;

  else if (state euqals( hello )) state= hi ;

  else if (state euqals( hi )) state= bye ;

  这就是 开关切换状态 是将state的状态从 hello 切换到 hi

  再切换到 bye ;在切换到 hello 好象一个旋转开关 这种状态改变就可以使用State模式了

  如果单纯有上面一种将 hello > hi > bye > hello 这一个方向切换

  也不一定需要使用State模式 因为State模式会建立很多子类 复杂化

  但是如果又发生另外一个行为:将上面的切换方向反过来切换 或者需要任意切换 就需要State了

  请看下例:

  public class Context

  private Color state=null;

  public void push()

  //如果当前red状态 就切换到blue

  if (state==Color red) state=Color blue;

  //如果当前blue状态 就切换到green

  else if (state==Color blue) state=Color green;

  //如果当前black状态 就切换到red

  else if (state==Color black) state=Color red;

  //如果当前green状态 就切换到black

  else if (state==Color green) state=Color black;

  Sample sample=new Sample(state);

  sample operate();

  

  public void pull()

  //与push状态切换正好相反

  if (state==Color green) state=Color blue;

  else if (state==Color black) state=Color green;

  else if (state==Color blue) state=Color red;

  else if (state==Color red) state=Color black;

  Sample sample =new Sample (state);

  sample operate();

  

  

  在上例中 我们有两个动作push推和pull拉 这两个开关动作 改变了Context颜色

  至此 我们就需要使用State模式优化它

  另外注意:但就上例 state的变化 只是简单的颜色赋值 这个具体行为是很简单的

  State适合巨大的具体行为 因此在 就本例 实际使用中也不一定非要使用State模式

  这会增加子类的数目 简单的变复杂

  例如: 银行帐户 经常会在Open 状态和Close状态间转换

  例如: 经典的TcpConnection Tcp的状态有创建 侦听 关闭三个

  并且反复转换 其创建 侦听 关闭的具体行为不是简单一两句就能完成的 适合使用State

  例如:信箱POP帐号 会有四种状态 start HaveUsername Authorized quit

  每个状态对应的行为应该是比较大的 适合使用State

  例如:在工具箱挑选不同工具 可以看成在不同工具中切换 适合使用State

  如具体绘图程序 用户可以选择不同工具绘制方框 直线 曲线 这种状态切换可以使用State

  如何使用

  State需要两种类型实体参与:

   state manager 状态管理器 就是开关 如上面例子的Context实际就是一个state manager

  在state manager中有对状态的切换动作

   用抽象类或接口实现的父类 不同状态就是继承这个父类的不同子类

  以上面的Context为例 我们要修改它 建立两个类型的实体

  第一步: 首先建立一个父类:

  public abstract class State

  public abstract void handlepush(Context c);

  public abstract void handlepull(Context c);

  public abstract void getcolor();

  

  父类中的方法要对应state manager中的开关行为 在state manager中

  本例就是Context中 有两个开关动作push推和pull拉

  那么在状态父类中就要有具体处理这两个动作:handlepush() handlepull();

  同时还需要一个获取push或pull结果的方法getcolor()

  下面是具体子类的实现:

  public class BlueState extends State

  public void handlepush(Context c)

  //根据push方法 如果是blue状态的切换到green ;

  c setState(new GreenState());

  

  public void handlepull(Context c)

  //根据pull方法 如果是blue状态的切换到red ;

  c setState(new RedState());

  

  public abstract void getcolor() return (Color blue)

  

  同样 其他状态的子类实现如blue一样

  第二步: 要重新改写State manager 也就是本例的Context:

  public class Context

  private Sate state=null; //我们将原来的 Color state 改成了新建的State state;

  //setState是用来改变state的状态 使用setState实现状态的切换

  pulic void setState(State state)

  this state=state;

  

  public void push()

  //状态的切换的细节部分 在本例中是颜色的变化 已经封装在子类的handlepush中实现 这里无需关心

  state handlepush(this);

  //因为sample要使用state中的一个切换结果 使用getColor()

  Sample sample=new Sample(state getColor());

  sample operate();

  

  public void pull()

  state handlepull(this);

  Sample sample =new Sample (state getColor());

  sample operate();

  

  

  至此 我们也就实现了State的refactorying过程

  以上只是相当简单的一个实例 在实际应用中 handlepush或handelpull的处理是复杂的

  /** */

  行为模式 Strategy

  Strategy是属于设计模式中 对象行为型模式 主要是定义一系列的算法 把这些算法一个个封装成单独的类

  Stratrgy应用比较广泛 比如 公司经营业务变化图

  可能有两种实现方式 一个是线条曲线 一个是框图(bar) 这是两种算法 可以使用Strategy实现

  这里以字符串替代为例 有一个文件 我们需要读取后 希望替代其中相应的变量

  然后输出 关于替代其中变量的方法可能有多种方法 这取决于用户的要求 所以我们要准备几套变量字符替代方案

  首先 我们建立一个抽象类RepTempRule 定义一些公用变量和方法:

  public abstract class RepTempRule

  protected String oldString= ;

  public void setOldString(String oldString)

  this oldString=oldString;

  

  protected String newString= ;

  public String getNewString()

  return newString;

  

  public abstract void replace() throws Exception;

  

  在RepTempRule中 有一个抽象方法abstract需要继承明确 这个replace里其实是替代的具体方法

  我们现在有两个字符替代方案

   将文本中aaa替代成bbb;

   将文本中aaa替代成ccc;

  对应的类分别是RepTempRuleOne RepTempRuleTwo

  public class RepTempRuleOne extends RepTempRule

  public void replace() throws Exception

  //replaceFirst是jdk 新特性

  newString=oldString replaceFirst( aaa bbbb )

  System out println( this is replace one );

  

  

  public class RepTempRuleTwo extends RepTempRule

  public void replace() throws Exception

  newString=oldString replaceFirst( aaa ccc )

  System out println( this is replace Two );

  

  

  第二步 我们要建立一个算法解决类 用来提供客户端可以自由选择算法

  public class RepTempRuleSolve

  private RepTempRule strategy;

  public RepTempRuleSolve(RepTempRule rule)

  this strategy=rule;

  

  public String getNewContext(Site site String oldString)

  return strategy replace(site oldString);

  

  public void changeAlgorithm(RepTempRule newAlgorithm)

  strategy = newAlgorithm;

  

  

  调用如下:

  public class test

  

  public void testReplace()

  //使用第一套替代方案

  RepTempRuleSolve solver=new RepTempRuleSolve(new RepTempRuleSimple());

  solver getNewContext(site context);

  //使用第二套

  solver=new RepTempRuleSolve(new RepTempRuleTwo());

  solver getNewContext(site context);

  

  

  

  我们达到了在运行期间 可以自由切换算法的目的

  实际整个Strategy的核心部分就是抽象类的使用 使用Strategy模式可以在用户需要变化时 修改量很少 而且快速

  Strategy和Factory有一定的类似 Strategy相对简单容易理解 并且可以在运行时刻自由切换

  Factory重点是用来创建对象

  Strategy适合下列场合:

   以不同的格式保存文件;

   以不同的算法压缩文件;

   以不同的算法截获图象;

   以不同的格式输出同样数据的图形 比如曲线 或框图bar等

  /** */

  行为模式 Mediator

  Mediator定义:

  用一个中介对象来封装一系列关于对象交互行为

  为何使用Mediator?

  各个对象之间的交互操作非常多;每个对象的行为操作都依赖彼此对方

  修改一个对象的行为 同时会涉及到修改很多其他对象的行为 如果使用Mediator模式

  可以使各个对象间的耦合松散 只需关心和 Mediator的关系

  使多对多的关系变成了一对多的关系 可以降低系统的复杂性 提高可修改扩展性

  如何使用?

  首先 有一个接口 用来定义成员对象之间的交互联系方式:

  public interface Mediator

  Meiator具体实现 真正实现交互操作的内容:

  public class ConcreteMediator implements Mediator

  //假设当前有两个成员

  private ConcreteColleague colleague = new ConcreteColleague ();

  private ConcreteColleague colleague = new ConcreteColleague ();

  

  

  再看看另外一个参与者:成员 因为是交互行为 都需要双方提供一些共同接口

  这种要求在Visitor Observer等模式中都是相同的

  public class Colleague

  private Mediator mediator;

  public Mediator getMediator()

  return mediator;

  

  public void setMediator( Mediator mediator )

  diator = mediator;

  

  

  public class ConcreteColleague

  public class ConcreteColleague

  每个成员都必须知道Mediator 并且和 Mediator联系 而不是和其他成员联系

  至此 Mediator模式框架完成 可以发现Mediator模式规定不是很多

  大体框架也比较简单 但实际使用起来就非常灵活

  Mediator模式在事件驱动类应用中比较多 例如界面设计GUI ;聊天 消息传递等

  在聊天应用中 需要有一个MessageMediator 专门负责request/reponse之间任务的调节

  MVC是J EE的一个基本模式 View Controller是一种Mediator 它是Jsp和服务器上应用程序间的Mediator

  /** */

  行为模式 Interpreter

  Interpreter定义:

  定义语言的文法 并且建立一个解释器来解释该语言中的句子

  Interpreter似乎使用面不是很广 它描述了一个语言解释器是如何构成的

  在实际应用中 我们可能很少去构造一个语言的文法 我们还是来简单的了解一下:

  首先要建立一个接口 用来描述共同的操作

  public interface AbstractExpression

  void interpret( Context context );

  

  再看看包含解释器之外的一些全局信息

  public interface Context

  AbstractExpression的具体实现分两种:终结符表达式和非终结符表达式:

  public class TerminalExpression implements AbstractExpression

  public void interpret( Context context )

  

  对于文法中没一条规则 非终结符表达式都必须的:

  public class NonterminalExpression implements AbstractExpression

  private AbstractExpression successor;

  public void setSuccessor( AbstractExpression successor )

  this successor = successor;

  

  public AbstractExpression getSuccessor()

  return successor;

  

  public void interpret( Context context )

  

  /** */

  行为模式 Visitor

  Visitor定义

  作用于某个对象群中各个对象的操作 它可以使你在不改变这些对象本身的情况下 定义作用于这些对象的新操作

  在Java中 Visitor模式实际上是分离了collection结构中的元素和对这些元素进行操作的行为

  为何使用Visitor?

  Java的Collection(包括Vector和Hashtable)是我们最经常使用的技术

  可是Collection好象是个黑色大染缸 本来有各种鲜明类型特征的对象一旦放入后 再取出时 这些类型就消失了

  那么我们势必要用If来判断 如:

  Iterator iterator = erator()

  while (iterator hasNext())

  Object o = iterator next();

  if (o instanceof Collection)

  messyPrintCollection((Collection)o);

  else if (o instanceof String)

  System out println( +o toString()+ );

  else if (o instanceof Float)

  System out println(o toString()+ f );

  else

  System out println(o toString());

  

  在上例中 我们使用了 instanceof来判断 o的类型

  很显然 这样做的缺点代码If else if 很繁琐 我们就可以使用Visitor模式解决它

  如何使用Visitor?

  针对上例 我们设计一个接口visitor访问者:

  public interface Visitor

  

  public void visitCollection(Collection collection);

  public void visitString(String string);

  public void visitFloat(Float float);

  

  在这个接口中 将我们认为Collection有可能的类的类型放入其中

  有了访问者 我们需要被访问者 被访问者就是我们Collection的每个元素Element

  我们要为这些Element定义一个可以接受访问的接口(访问和被访问是互动的

  只有访问者 被访问者如果表示不欢迎 访问者就不能访问)

  我们定义这个接口叫Visitable 用来定义一个Accept操作 也就是说让Collection每个元素具备可访问性

  public interface Visitable

  

  public void accept(Visitor visitor);

  

  好了 有了两个接口 我们就要定义他们的具体实现(Concrete class):

  public class ConcreteElement implements Visitable

  

  private String value;

  public ConcreteElement(String string)

  value = string;

  

  //定义accept的具体内容 这里是很简单的一句调用

  public void accept(Visitor visitor)

  visitor visitString(this);

  

  

  再看看访问者的Concrete实现:

  public class ConcreteVisitor implements Visitor

  

  //在本方法中 我们实现了对Collection的元素的成功访问

  public void visitCollection(Collection collection)

  Iterator iterator = erator()

  while (iterator hasNext())

  Object o = iterator next();

  if (o instanceof Visitable)

  ((Visitable)o) accept(this);

  

  public void visitString(String string)

  System out println( +string+ );

  

  public void visitFloat(Float float)

  System out println(float toString()+ f );

  

  

  在上面的visitCollection我们实现了对Collection每个元素访问

  只使用了一个判断语句 只要判断其是否可以访问

  至此 我们完成了Visitor模式基本架构

  使用Visitor模式的前提

  对象群结构中(Collection) 中的对象类型很少改变 也就是说访问者的身份类型很少改变

  如上面中Visitor中的类型很少改变 如果需要增加新的操作 比如上例中我们在ConcreteElement具体实现外

  还需要新的ConcreteElement ConcreteElement

  可见使用Visitor模式是有前提的 在两个接口Visitor和Visitable中

  确保Visitor很少变化 变化的是Visitable 这样使用Visitor最方便

  如果Visitor也经常变化 也就是说 对象群中的对象类型经常改变 一般建议是

  不如在这些对象类中逐个定义操作 但是Java的Reflect技术解决了这个问题

cha138/Article/program/Java/gj/201311/27375

相关参考

知识大全 Java程序性能优化-代理模式(6)

Java程序性能优化-代理模式(6)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!   

知识大全 怎么才能学好java程式设计呢 除了要看java程式设计思想之外

怎么才能学好java程式设计呢除了要看java程式设计思想之外多练,多看别人怎么编,你可以拿别人的工程档案来看他们变成的思想的方法是什么java程式设计思想?什么水平的人都可以,只要你对Java感兴趣

知识大全 Java设计模式-----Command模式

Java设计模式-----Command模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  源自

知识大全 Java设计模式-----State模式

Java设计模式-----State模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  源自  

知识大全 Java设计模式之Strategy模式

Java设计模式之Strategy模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Strat

知识大全 Java设计模式之Observer模式

Java设计模式之Observer模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Obser

知识大全 Java设计模式之Command 模式

Java设计模式之Command模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  Comman

知识大全 java之单例设计模式

  设计模式解决某一类问题最行之有效的方法(java中有种通用设计模式)  单例设计模式解决一个类在内存中只存在一个对象  单例设计模式有两种方式  )饿汉式  先初始化对象当类一进内存就创建好对象 

知识大全 Java设计模式之Adapter模式

Java设计模式之Adapter模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  通常客户类(

知识大全 Java设计模式之计数代理模式

Java设计模式之计数代理模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  描述    计数代