知识大全 架构模式-界面组装器模式

Posted

篇首语:智者不为愚者谋,勇者不为怯者死。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 架构模式-界面组装器模式相关的知识,希望对你有一定的参考价值。

  本文提出了一种界面设计中的架构模式 界面组装器模式 它致力于分解界面 将界面和组装行为解耦 将界面逻辑处理与领域逻辑处理解耦 这样我们在开发GUI胖客户端界面应用时可以从众多的界面控制管理中解脱出来 而专注于我们的后台业务逻辑的开发 通过该模式 我们可以动态地组装我们的界面 我们甚至还可以在我们的界面中轻松地插入 transaction 事务或 session 会话管理

  本文将通过分析设计一个架构的过程来讲解该模式 从一个简单的设计模型开始 一步步走向一个完整的架构 借此也向大家展示一个架构设计的思维历程 另外 本文给出了 Eclipse SWT(Standard Widget Toolkit) 的示例

  问题引出

  界面设计常常是模式产生的根源 无论是架构模式 还是设计模式 比如 MVC 模式 Observer Facade 等 也是整个软件行业向前发展的动力 遗憾的是 即使在软件技术发达的今天 界面设计仍是软件设计中的难以突破的瓶颈之一 我们用过 Java swing 或 Eclipse SWT 作过项目的都知道 要将界面进行分解是很困难的 它不像我们的业务逻辑 可以方便地按职责分解到不同的类中去实现 因为各个业务逻辑之间耦合度很低 但界面逻辑不一样 你不可能将一个文本框的读取操作委任到另一个类中去 而且各个界面元素之间相互依赖 无法去除耦合 一般的做法只能是在界面元素的事件触发(比如按钮点击事件)时 将输入数据封装成一个数据对象传给后台的逻辑处理类来处理

  Eclipse 的 Wizard 框架在界面分解上提供了一种很好的实践 它可以将按钮区和其他界面区分离出来 用类似 MVC 的方式实现了 Wizard 框架 但这个实现并非没有瑕疵 一个缺点是 wizard 是一个 plug in 这样的话就减少了可重用性 不能移植到 eclipse 以外的环境 另一个缺点就是它引入了很大的复杂性 而且在一些对界面元素的控制上丧失了一些精细控制的能力 这可能是它过度地强调了自动化和用户扩展的方便性的缘故 比如 用户不能将自己的逻辑插入按钮区的按钮事件控制中 而只能在自定义区的界面元素 Listener 中设定按钮区状态 如果用户自定义的界面元素很多 就需要很多个 Listener 来组合判断一个按钮状态(如是否进行 下一步 ) 这样的话就很影响性能 而且无端地多了一堆复杂的逻辑判断 也就是说本来只需在按钮 Listener 事件中处理的逻辑现在要分散在各个界面元素的 Listener 中去处理 这也正是设计上一个值得反复强调的普遍问题 当你要保持架构或设计的完美性时必然会以丧失其他特性为代价 世上永远没有完美的东西 我们只关注适合我们的

  我下面要提出的这个架构模式的灵感来自于我的一个真实项目 一个用 RSA(Rational Sofare Architect)/Eclipse 建模的项目 在 RSA 环境中 读写模型都必须在一个特有的 context 下才能操作 这就意味着我在界面的启动之前必须封装好输入数据 关闭之后返回输出数据 而不是直接处理数据 必须对输入/输出数据对象进行封装 正如前面提到的 这种情况界面设计中很普遍 所以 在模式命名时我用了组装器 assembler 这个词 有一层意思是输入/输出数据对象的组装 另一层意思就是界面部件(界面元素的集合)的组装 这里的组装还有更深层次的涵义就是指界面部件的可装配性 可以在运行时动态组装 而且这个模式可以用任何语言(Java C++ 等)来实现 在这里我会从一个简单的设计模型开始 一步步走向一个完整的架构 借此也向大家展示一个架构设计的思维历程 本文中给出了 Eclipse SWT(Standard Widget Toolkit) 的示例

  界面分解

  在 Eclipse SWT 中 有几个重要的界面部件 一个是Shell 界面的最外层容器 类似 Java Swing 中的 Frame 另一个就是 Composite 界面元素的集合的容器 类似 Java Swing 中的 Panel 我们的界面分解将从 Composite 开始 (Shell 本身是不需要分解的) 我们可以在 Shell 中装配上一个空的 Composite 然后我们的具体界面元素都定义在这个 Composite 里 这样就把 Composite 逻辑从 Shell 中分离出来了 因此我们现在有了 个类(目前我们用概念类来表示)

   图 把 Composite 逻辑从 Shell 中分离出来

  

  Editor : 该类处理 Shell 的逻辑 如显示 show 关闭 close 它负责创建和销毁 EditorComposite

  EditorComposite: 该类处理 Composite 的界面逻辑 如创建界面元素

  有两点值得注意 第一 Editor 负责 EditorComposite 的创建和销毁 也就是生命周期的管理 那么我们可以想到 如果我们的界面需要 transaction 事务或 session 会话的管理 那么我们完全可以让 Editor 来负责这项职责 而不是分散在各个 EditorComposite 中 怎么扩展界面的事务功能可能会很复杂 这已经超出本文的讨论范围 我只是从架构的层面来分析可能有的可扩展性 第二 一个 Editor 可以包括多个 EditorComposite 比如我们的属性页 此时我们在Shell中定义的空的 Composite 将会是一个 TabFolder 还有一种情况 就是我们可以根据某种逻辑来判断我们需要装配哪个 EditorComposite 这就要求我们有一个装配的行为

  界面部件装配

  当我们的装配逻辑很简单时 我们可以定义一个 assemble() 方法来负责装配行为 但是当我们的界面需要组装一系列 EditorComposite 时 就会牵涉到选择逻辑 选择逻辑不一定很复杂 但我们还是应该把这种行为从 Editor 中分离出来 这样 Editor 可以集中精力负责与用户交互方面的职责 而装配行为被分配到一个新的类 EditorAssembler 中 这样做还有一个好处 就是我们一旦有新的 EditorComposite 需要添加时 我们只需要改变 EditorAssembler 的代码 而不用修改 Editor 的代码 这就把变化隔离出来 对 Editor 的修改关闭 对装配行为的扩展开放 这正是面向对象设计领域反复强调的基本原则 开放 封闭原则(Open Close Principle) 经过重构后的架构如下图

  图 重构后的架构

  

  EditorAssembler 该类处理 EditorComposite 的创建 还包括多个 EditorComposite 的选择逻辑

  这里的选择逻辑我们可以用 if/else 或 switch/case 来硬编码 如果逻辑不是很复杂而且今后的修改不会太频繁的话 用这种方法就足够了 当然可以考虑将多个 EditorComposite 的装载信息专门用一个资源/信息类来存储 target=_blank>存储 这在 EditorComposite 比较多的情况下很有效 这样每次添加 EditorComposite 就只需要改变这个资源类 这是一个很有用的建模原则(为了简化我们的核心模型 我在这里不将这个资源类表示出来)

  如果进一步考虑到我们的组装逻辑会比较复杂 或会比较容易改变 甚至在运行时动态改变 我们就可以将众多的 EditorComposite 和复杂的逻辑存储在一个元数据文件中 如 XML 或配置文件 这样 有新的 EditorComposite 需要支持 或修改装配逻辑时 不用修改 EditorAssembler 类 只要修改元数据文件即可 这样就可以很动态的配置我们的界面 这里会有一个架构权衡的问题 元数据由它的优点 也有它的缺点 其一 必须编写解析它的类 复杂性增加了 其二 不需要编译是它的优点也是它的缺点 对 XML 或配置文件我们可以随意修改 只有在运行时发现异常才知道改错了 而且也可能被人蓄意破坏掉 所以我们只在真的需要很频繁地修改 EditorComposite 的配置或经常需要增加 EditorComposite 时才采用元数据方案 在这里我倾向于采用资源类方案

  IO 数据装配

  模型设计进行到这里 我们似乎缺少了对数据流的建模 在一个标准的界面程序中 我们首先会有一组输出数据 比如按 OK 按钮之后 我们需要将界面元素上的输入信息输出到后台逻辑类来处理或直接调用好几个逻辑类分别处理不同的界面元素输入信息了 我们一般习惯上可能直接将这个数据传递到逻辑类来处理 这样做三个缺点 其一 如果我们的数据读写处理要求必须在特定的 context 中才能进行 这样的话我们不能在界面中直接调用后台逻辑处理类了 其实这种限制并不罕见 在一些涉及底层(比如协议层)的开发时 经常会碰到只能读不能写的情况 其二 UI 的可替代性差 假如我们今后需要一种方案可以在运行时可以替换不同的 UI 但输出的数据是一样的 也就是说后台逻辑处理完全一致 那么这种情况我们就需要每一个 UI 自己去调用后台逻辑类 重复编码 而且可能由于程序员的失误每一个 UI 用了一个逻辑类 从而导致一个完全相同行为的类有了好几个不一致实现版本 这样不仅严重违反了面向对象设计 而且还可能产生难以预料的 bug 难以维护 其三 UI 的可重用性差 对于上面多个 UI 对应一种逻辑处理的例子 由于 UI 依赖了后台逻辑类 如果今后要修改逻辑类结构的话 我们就需要修改每一个 UI 如果我们还有一种需求是要支持一个 UI 在不同的环境下需要不同的后台逻辑类时 我们可能要专门在一个 UI 中设置一个属性来标识后台将要使用的逻辑类 这会很复杂

  解决上面几个缺点只有一种方法 就是将后台逻辑类与 UI 解耦 如果我们把要处理的输出数据打包成一个输出数据对象从界面统一输出 再由 UI 的调用者决定调用哪一个后台逻辑类来处理数据 而不是 UI 自己决定调用行为

  还有一个输入数据对象就很好理解了 我们调用 UI 时 可能某些界面元素需要的从环境中动态装载数据 比如一个下列列表 还有一些我们上一次配置好的数据这次需要更新 也需要将已有数据导入 所以我们需要一个输入数据对象 这就得到下面的模型

  图 输入数据对象

   src= //img educity cn/img_ / / / jpg border= ffan= done >

  InputDataObject 该类封装了输入数据 由 EditorComposite 负责解析这些数据

  OutputDataObject 该类封装了输出数据 由 EditorComposite 负责产生这些数据

  Editor 负责传输这两个数据对象

  从上面的模型我们可以看出 Editor 类其实相当于一个 Facade 所有的界面与用户的交互都由它负责集中调度管理 Editor 会将装配行为分配给 EditorAssembler 类来处理 它还负责临时存储输入输出数据 当然如果我们有类似 transaction 或 session 之类的处理会由 Editor 委派到别的相关类去处理 应用 Facade 设计模式 我们可以给 Editor 改个名字叫 EditorFacade 这样更能体现设计者的意图 千万不要忽视类的命名 设计是一门严肃的科学 每一个细节我们都不能苟且 对架构的设计更要严谨 命名可以起到沟通的作用 还能起到提醒的功能 EditorFacade 提醒我们以后要给它添加新的行为是记住它是一个 Facade 不能将不相干的职责分配进来

  另外 我发现添加了 InputDataObject 类后 EditorComposite 就有两个职责 装载界面元素初始化数据(一些需要从环境中动态获得的输入数据 从 InputDataObject 对象中获得)和显示上一次编辑的数据(也从 InputDataObject 对象中获得) 我们定义两个方法来分别处理 loadDataInfo() 装载初始化数据;showPreInfo() 显示上一次编辑的数据 当然 一般来说这两个方法是私有的 private 因为这是 EditorComposite 自身的内部逻辑 但我们在这个架构中让它成为公有的 public 是因为我们可以在 EditorAssembler 类中集中控制它的调用 而且每一个 EditorComposite 都会有装载初始化数据和显示已有数据的行为 那么为什么不抽象出来呢 以便让 EditorComposite 的开发提供者更清楚自己的职责 虽然这么做有点破坏 EditorComposite 的封装性和其中方法的私密性 但从架构的角度来讲这种破坏是合适的 值得的

  再看看前面的 EditorAssembler 类 它其实有两个职责 一个是创建 EditorComposite 还有一个就是从几个 EditorComposite 选择出一个的判断逻辑 如果我们把这两个不相干的职责解耦 应用 Factory 设计模式 就可以将创建 EditorComposite 的工作委任给一个 EditorCompositeFactory 的新类

  经过以上几项重构后得到以下概念类模型

  图 概念类模型

   src= //img educity cn/img_ / / / jpg border= ffan= done >

  经过上面的分析建模 我们可以开始实现架构了 从上面的概念模型我们可以很容易地抽象出相应的接口来 首先 我们看看 EditorFacade 类 基于我们上面的讨论 不同的界面可能有不同的需求 比如有的要支持 transaction 事务 那么 EditorFacade 的实现就会不同 所以我们有必要提取出一个接口来表示 下面列出了这个接口 IEditorFacade

  清单 IEditorFacade java

Code highlighting produced by Actipro CodeHighlighter (freeware) > public interface IEditorFacade   public void show();   public IInputDataObject getInputData();   public void setInputData(IInputDataObject inputData);   public IOutputDataObject getOutputData();   public void setOutputData(IOutputDataObject outputData);   public boolean isFinishedOK();   public Composite getRootComposite();   public void setAssembler(IEditorAssembler assembler);   public void close(boolean status);   

  那么 EditorFacade 类的部分代码如下

   清单 EditorFacade java

Code highlighting produced by Actipro CodeHighlighter (freeware) > public class EditorFacade implements IEditorFacade   private Shell shell;   // validate if editor is closed with OK or Cancel   private boolean finishedOK;   // input data   private IInputDataObject inputData;   // output data   private IOutputDataObject outputData;   private Composite posite;   private IEditorAssembler assembler;   private void createSShell()   shell = new Shell();   shell setLayout(new GridLayout());   createComponent();      private void createComponent()   posite = new Composite(shell SWT NONE);   ………   assembler create(this);      public void show()   this shell open();   assembler showPreInfo();      public EditorFacade(IEditorAssembler assembler IInputDataObject inputData)   this assembler = assembler;   this inputData = inputData;   this createSShell();      public Composite getRootComposite()   return posite;      public void close(boolean status)   finishedOK = status;   this shell close();      

  下一步 我们将两个 IO 数据类定义出来 很显然 不同的界面会有不同的输入输出数据 在这里我们只能定义出两个抽象的接口 IInputDataObject 和 IOutputDataObject 它们继承了序列化 java io Serializable 接口 里面并无其它内容 这里注意一点 空的接口并非无意义 它可以起到标识的作用 另外 它隐藏了具体实现 在传递数据时传递者不用知道具体数据内容 这样传递者类具有更好的重用性 而且具体数据类也不用暴露给不该知道它的类 传递者类 这正是另一个面向对象的基本原则 迪米特法则(LoD) 不要和陌生人说话 下面给出 IInputDataObject 的清单

  清单 IInputDataObject java 

Code highlighting produced by Actipro CodeHighlighter (freeware) > public interface IInputDataObject extends Serializable   

  接下来 我们看看 EditorAssembler 类的实现 根据前面的讨论 它封装了界面的装配逻辑 一定会被修改的 那么我们就需要一个接口 IEditorAssembler 来规范它的行为 在这里我还给出了一个抽象类 AbstractEditorAssembler 实现了装载单个 EditorComposite 的方法 另外我还给出了一个具体的 EditorAssembler 类 这是一个每次只装载一个 EditorComposite 的例子 代码清单如下

   清单 IEditorAssembler java

Code highlighting produced by Actipro CodeHighlighter (freeware) >  public interface IEditorAssembler   /**   * create editor body and init   * @param editor   */   public void create(IEditorFacade editor);   /**   * create editor posite   * @param editor   * @param positeClassID   * :posite class name e g test view TestComposite   * @return   */   public IEditorComposite createComposite(IEditorFacade editor   String positeClassID);   /**   * show exist info in UI for update   */   public void showPreInfo();     public interface IEditorAssembler   /**   * create editor body and init   * @param editor   */   public void create(IEditorFacade editor);   /**   * create editor posite   * @param editor   * @param positeClassID   * :posite class name e g test view TestComposite   * @return   */   public IEditorComposite createComposite(IEditorFacade editor   String positeClassID);   /**   * show exist info in UI for update   */   public void showPreInfo();   

          清单 AbstractEditorAssembler java

Code highlighting produced by Actipro CodeHighlighter (freeware) > public abstract class AbstractEditorAssembler implements IEditorAssembler   public IEditorComposite createComposite(IEditorFacade editor   String positeClassID)   IEditorComposite body;   body = EditorCompositeFactory createComposite(positeClassID editor);   body create(editor getRootComposite());   body setEditor(editor);   return body;      …………………………………    相关rss > 相关keyword >

  清单 StandaloneEditorAssembler java

Code highlighting produced by Actipro CodeHighlighter (freeware) > public class StandaloneEditorAssembler extends AbstractEditorAssembler   private String positeClassID;   private IEditorComposite bodyComposite;   /**   *   * @param positeClassID   * :posite class qulified name e g ibm XXComposite;   */   public StandaloneEditorAssembler(String positeClassID)   positeClassID = positeClassID;      public void create(IEditorFacade editor)   bodyComposite = createComposite(editor positeClassID);   if (bodyComposite != null)   bodyComposite loadDataInfo();      public void showPreInfo()   bodyComposite showPreInfo();      

  接下来 是 EditorCompositeFactory 的实现 这个类的实现比较简单 只是根据类名产生类

  清单 EditorCompositeFactory java

Code highlighting produced by Actipro CodeHighlighter (freeware) > public class EditorCompositeFactory   /**   * create IEditorComposite   * @param clsName   * @param editor   * @return   */   public static IEditorComposite createComposite(String clsName   IEditorFacade editor)   IEditorComposite posite = null;   try   Class cls = Class forName(clsName);   if (cls != null)   posite = (IEditorComposite) cls newInstance();    catch (Exception e)   e printStackTrace();      if (posite != null)   posite setEditor(editor);      return posite;      

  最后 就是 EditorComposite 的实现了 很显然每个界面的 EditorComposite 都不一样 所以我们在这里只定义了一个接口来规范一下行为 具体的 EditorComposite 实现我会在代码附件中的测试包中给出

  清单 IEditorComposite java

Code highlighting produced by Actipro CodeHighlighter (freeware) > public interface IEditorComposite   /** set up posite UI */   public void create(Composite parent);   /** set the current editor for shell close and data set */   public void setEditor(IEditorFacade editor);   /** show previous data information in UI */   public void showPreInfo();   public void loadDataInfo();   

  下面 我们编写一些测试代码来测试它 这个测试应用是要编写一个电话簿 为了简单起见我只定义了一个 EditorComposite PhoneBookComposite 在编写组装逻辑时也只是示例性地改变了一下界面的标题和尺寸 (详细代码见代码下载)

  清单 PhoneBookEditorAssembler java

Code highlighting produced by Actipro CodeHighlighter (freeware) > public void create(IEditorFacade editor)   if (positeType == )   //it is a phone book   bodyComposite = createComposite(editor test PhoneBookComposite );   | |   | XML error: The previous line is longer than the max of characters |   editor getShell() setText( Phone Book );   editor getShell() setSize( );   editor getShell() redraw();   if (bodyComposite != null)   bodyComposite loadDataInfo();    else if (positeType == )   //it is a memo book   bodyComposite = createComposite(editor test PhoneBookComposite );   | |   | XML error: The previous line is longer than the max of characters |   editor getShell() setText( Memo Book );   editor getShell() setSize( );   editor getShell() redraw();   if (bodyComposite != null)   bodyComposite loadDataInfo();      

  清单 Main java

Code highlighting produced by Actipro CodeHighlighter (freeware) >  public static void main(String[] args)   //定义PhoneBook EditorAssembler   IEditorAssembler assembler = new PhoneBookEditorAssembler( );   //定义PhoneBook 输入数据   IInputDataObject inputData = new PhoneBookInputDO( LYL );   //定义PhoneBook editor   EditorFacade editor = new EditorFacade(assembler inputData);   editor show();   if (editor isFinishedOK())   //取出PhoneBook 输出数据   if (editor getOutputData() instanceof PhoneBookOutputDO)   PhoneBookOutputDO outputData = (PhoneBookOutputDO) editor    getOutputData();   String name = outputData getName();   String phone = outputData getPhone();   System out println( name: + name + ; phone: + phone);         

  接下来 我们可以看一下架构的实现模型 注意 我在画下面的 UML 图时采用了分层的方式 所有的接口都会在上面一层 实现在下面一层 这种分层画 UML 图的方法有助于我们理清架构的思路 也便于与开发组的其他成员沟通

  图 架构的实现模型

   alt= src= //img educity cn/img_ / / / jpg width= border= ffan= done >

  至此 我们完成了界面组装器的核心架构的实现 注意 这只是一种实现 并不是界面组装模式的全部 作为一种模式 它必须有更广的外延 下面我们将要探讨它的模式本质

  这个模式是一种架构模式 模式的定义有三个要素 问题 环境 解决方案 这在前面我们已经详细地论述过了 在这里我们讨论一下其他的参量 每个模式都有它自己独特的价值观 那么界面组装器模式给我们提供了什么样的价值观呢?

  首先 它的精髓在于这种分解界面 将界面和组装行为解耦的设计思想 这在拥有多个界面的应用中很有益处 当界面多的时候 如果没有一个比较集中的调度控制方式来对这些界面进行管理 就会形成界面行为无法规范 风格各异 更难以作 transaction 事务或 session 会话控制 这在小型应用开发中也许不很明显 但在一个大中型应用中对分散的不规范的界面行为进行控制将会是一场恶梦 到最后可能整个开发组都沉浸于 bug 的修复和界面修改中 而无暇顾及领域逻辑代码的编写 而通过将界面和组装行为解耦就可以让开发人员集中精力于界面逻辑和领域逻辑的开发 而不用每一个界面都去编写管理界面的代码 其实这也是模式化的一个优点 模式可以优化我们的架构 可以规范开发行为 因此也会节省开发成本

  其二 它将界面逻辑处理与领域逻辑处理(也就是数据逻辑处理)解耦 我们将数据输入输出从界面模型中抽取出来 没有与界面耦合在一起 这就获得巨大的好处 第一 我们可以在界面之外来处理数据 在我们的领域类中处理这些数据 也就是说界面只是提供了一个定义数据的载体 而这些数据是被领域逻辑类使用的 而我们开发的主要精力也应该放在处理业务逻辑的领域类上 第二 现在我们将界面和领域类解耦 这样我们的界面和领域类都可以独立地变化 相互之间没有任何依赖 这就很方便于我们开发人员的分工 编写界面的开发组不用依赖于编写后台逻辑类的开发组 第三 在做单元测试 unit test 时 开发后台逻辑类的人员可以单独测试领域类 而开发界面的人员也可以单独测试界面逻辑 第四 当我们有多套界面机制时 我们的后台逻辑类可以很方便地接插上去 比如我们要支持 GUI(SWT/Java Swing)和 Web 方式 那么我们的领域类和数据类无需任何更改就可以方便的切换 第五 我们还能获得好处 就是数据类的可重用 如果我们没有输入输出数据类的封装行为 那可能我们会将各条数据散落在界面类中直接处理 这样当你要换一种界面机制时就必须重写这部分逻辑 无法重用

  作为一种模式 它会有很多的变体 也就是说它不拘泥于我们给出的这种外在实现方式 它还有其它的实现 例子中我们只是组装一个 EditorComposite 我们当然可以一次组装几个 EditorComposite 比如一个复杂的界面会有好几个 EditorComposite 组成 或者像属性页 并列著有好几个 EditorComposite 我们只需要自己实现一个组装器类 Assembler 就可以 又或者我们可以在运行界面时动态地在几个界面之间切换界面 这可能会复杂一些 也受限于平台或语言的技术实现 但也并非不可实现

  对于该模式的适用性 我想它主要适用于那些每次装载一个 EditorComposite 或属性页的情况 至于是否可以作为 Wizard 向导界面的实现架构 还需进一步探索 不过从这个模式的概念层次上来看 它的关键的价值观是完全可以用于实现 Wizard 向导界面的 只不过具体实现时可能会对现在的架构变动较大 另外这个模式主要适用于 GUI 客户端界面 对于 Web 形式的界面 已经有别的模式可以考虑

  我们还可以讨论一下界面组装器模式与别的模式之间的关系 在界面架构界我们已经有了大名鼎鼎的 MVC 模式 为什么还需要界面组装器模式呢?虽然 MVC 模式解决的也是界面与领域逻辑处理的解耦 但它的出发点主要是针对一个业务逻辑处理后会有好几个界面同时需要更新显示 也就是说它的贡献在于他的及时传播数据变更的能力 这和我们的模式是不一致的 我们主要解决界面的分解组装和数据剥离的问题 当然他们在结构上有些相似之处 我们的 EditorFacade 有点像 MVC 中的控制器

  结束语

cha138/Article/program/Java/gj/201311/27337

相关参考

知识大全 浅析MVC模式与三层架构的区别

浅析MVC模式与三层架构的区别  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  浅析MVC模式与三

知识大全 .NET面向上下文、AOP架构模式

.NET面向上下文、AOP架构模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  上下文Cont

知识大全 iphone6不开机,能进dfu模式,刷机停留在等待iphone界面

iphone6不开机能进dfu模式,刷机停留在等待iphone界面是怎么回事?正在更新新版本1、更新到最新版本的iTunes;2、进入DFU恢复模式进行恢复;(DFU模式:.将你的iPhone关机;.

知识大全 windows update更新失败,还原设置,为啥一直在那个界面,安全模式都进不去系统

windowsupdate更新失败,还原设置,为啥一直在那个界面,安全模式都进不去系统这个界面需要等待一段时间的,如果超过30分钟,建议如下操作:重新启动电脑一启动就不停的按F8选择进入安全模式一般在

知识大全 Java设计模式之迭代器模式

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

知识大全 设计模式-行为型-迭代器模式(Iterator)

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

知识大全 php设计模式介绍之迭代器模式

  《PHP设计模式介绍》第八章迭代器模式  类中的面向对象编程封装应用逻辑类就是实例化的对象每个单独的对象都有一个特定的身份和状态单独的对象是一种组织代码的有用方法但通常你会处理一组对象或者集合  

知识大全 C#中的Iterator迭代器模式

C#中的Iterator迭代器模式  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!迭代器模式我们在平

知识大全 老生常谈:迭代器模式

    有很多方法可以把对象堆起来成为一个集合你可以把它们放进数组堆栈列表或者是散列表中这是你的自由    迭代器模式定

知识大全 百度索尼版如何设置夜间模式

百度索尼版如何设置夜间模式百度索尼版如何设置夜间模式的操作步骤如下:1、在手机中打开百度客户端,来到主页,再点击底部的”我“。2、在”我“界面,找到最底部的“设置”选项并点击进入设置。3、在设置界面,