知识大全 怎样设计合适的接口

Posted

篇首语:捐躯赴国难,视死忽如归。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 怎样设计合适的接口相关的知识,希望对你有一定的参考价值。

  摘要 我们在设计系统接口时 经常会遇到这样的问题   我们的接口应该提供多少方法才合适?   我们的接口应该提供 原子方法 还是 复合方法 ?   我们的接口是否应该封装(或者 能否封装)所有的细节?   接口的设计需要考虑用户的使用习惯 使用的方便程度 使用的安全程度 根据我的编程经验 下面会详细讨论接口设计的 个需要权衡的方面 接口的单一化 & 复合化   接口   接口提供了不同系统之间或者系统不同组件之间的界定 在软件中 接口提供了一个屏障 从而从实现中分离目标 从具体中分离抽象 从作者中分离用户     站在用户的角度看 一个接口建立并命名了一个目标对象的使用方法 一些约束(例如 编译时的类型系统 运行时的异常机制及返回值)使得类作者的目的得以体现和加强 供给(affordances)指事物的被感知的真实的属性 这些属性可以决定事物使用的可能方法 供给提供了对事物操作的线索     类设计者的一个职责便是在接口中减小约束与供给之间的隔阂 匹配目标以及一定程度上的自由度 尽可能减小错误使用目标对象的可能     封装   对于封装来说 远不止数据私有那么简单 在设计中 封装往往会涉及到自我包含(self containment) 如果一个类需要你知道如何调用它方法(e g 在一个线程的环境中 在一个方法调用后调用另一个方法 你必须明确地同步对象) 那么它的封装性就不如将所有这些全部包含并隐藏的类(e g 这个类是thread safe的)好 前一个设计存在着设计的漏洞 它的许多限定条件是模糊的 而且把部分责任推给了用户 而不是让类提供者做这些工作来完成类的设计     在空间或者时间上分离方法的执行(例如 线程 远程方法调用 消息队列) 能够对设计的正确性和效率产生意义深远的影响 这种分离带来的结果是不可忽视的     并发引入了不确定性和环境(context)选择的开销   分布引入了回调的开销 这些开销可能不断增加 而且会导致错误   这些是设计的问题 修改它们可不是象修改bug那样简单     如果一个接口主要由存取方法(set和get方法)组成 每个方法都相应的直接指向某个私有域 那么它的封装性会很差 接口中的域存取方法通常是不会提供信息的 他们在对象的使用中不能通讯 简单化和抽象化 这通常会导致代码冗长 并且容易出错     所以 我们首先考虑接口设计的第一个原则     命令与查询分离(Command Query Separation)   要求 保证一个方法不是命令(Command)就是查询(Query)    定义     查询 当一个方法返回一个值来回应一个问题的时候 它就具有查询的性质     命令 当一个方法要改变对象的状态的时候 它就具有命令的性质     通常 一个方法可能是纯的Command模式或者是纯的Query模式 或者是两者的混合体 在设计接口时 如果可能 应该尽量使接口单一化 保证方法的行为严格的是命令或者是查询 这样查询方法不会改变对象的状态 没有副作用(side effects) 而会改变对象的状态的方法不可能有返回值 也就是说 如果我们要问一个问题 那么就不应该影响到它的答案 实际应用 要视具体情况而定 语义的清晰性和使用的简单性之间需要权衡     例如 在java util Iterator中 hasNext可以被看作一种查询 remove是一种命令 next合并了命令和查询   public interface Iterator  boolean hasNext();  Object next();  void remove();            这里 如果不将一个Iterator对象的当前值向前到下一个的话 就不能够查询一个Iterator对象 如果没有提供一个复合方法next 我们将需要定义一系列的命令方法 例如 初始化(initialization) 继续(continuation) 访问(access)和前进(advance) 它们虽然清晰定义了每个动作 但是 客户代码过于复杂   for(initialization; continuation condition; advance)   access for use             将Command和Query功能合并入一个方法 方便了客户的使用 但是 降低了清晰性 而且 可能不便于基于断言的程序设计并且需要一个变量来保存查询结果   Iterator iterator = erator();  while(iterator hasNext();)  Object current = iterator next();   use current         下面 我们考虑接口设计的第二个原则     组合方法(Combined Method)   组合方法经常在线程和分布环境中使用 来保证正确性并改善效率     一些接口提供大量的方法 起初 这些方法看来是最小化的 而且相关性强 然而 在使用的过程中 一些接口显现得过于原始 它们过于简单化 从而迫使类用户用更多的工作来实现普通的任务 并且 方法之间的先后顺序及依赖性比较强(即 暂时耦合) 这导致了代码重复 而且非常麻烦和容易出错     一些需要同时执行成功的方法 在多线程 异常 和分布的情况下会遇到麻烦 如果两个动作需要同时执行 它们由两个独立的方法进行描述 必须都完全成功的执行 否则会导致所有动作的回滚     线程的引入使这种不确定性大大增加 一系列方法同时调用一个易变的(mutable)对象 如果这个对象在线程之间共享 即使我们假设单独的方法是线程安全的 也无法确保结果是意料之中的 看下面对Event Source的接口 它允许安置句柄和对事件的查询   interface EventSource  Handler getHandler(Event event);  void installHandler(Event event Handler newHandler);            线程之间的交叉调用可能会引起意想不到的结果 假设source域引用一个线程共享的对象 对象很可能在 之间被另一个线程安装了一个新的句柄   class EventSourceExample  public void example(Event event Handler newHandler)  oldHandler = eventSource getHandler(event); //   //对象很可能在这里被另一个线程安装了一个新的句柄  eventSource installHandler(event newHandler); //     private EventSource eventSource;  private Handler oldHandler;            为了解决问题 也需要由类的使用者而不是类的设计者来完成   class EventSourceExample  public void example(Event event Handler newHandler)  synchronized(eventSource)  oldHandler = eventSource getHandler(event);  eventSource installHandler(event newHandler);      private EventSource eventSource;  private Handler oldHandler;            我们假设 目标对象eventSource是远程的 执行每一个方法体的时间和通讯的延迟相比是很短的 在这个例子中 eventSource的方法被调用了两次 并可能在其他的实例中重复多次 因而 开销也是至少两倍     此外还有一个问题是对外部的synchronized同步块的使用需求 对synchronized块的使用之所以会失败 主要因为我们通过代理对象来完成工作 所以 调用者的synchronized块 同步的是代理对象而不是最终的目标对象 调用者不可能对其行为做太多的保证     Combined Method必须在分布的环境 或者 线程环境中同时执行 它反映了用户直接的应用 恢复策略和一些笨拙的方法被封装到Combined Method中 并简化了接口 减少了接口中不需要的累赘 Combined Method的效果是支持一种更像事务处理风格的设计     在一个组合的Command Query中提供一个单独的Query方法通常是合理的 提供分离的Command方法是不太常见的 因为Combined Method可以完成这一工作 只要调用者简单的忽略返回结果 如果返回一个结果招致一个开销的话 才可能会提供一个单独的Command方法     回到前一个例子中 如果installHandler method返回上一次安装的句柄 则设计变得更加简单和独立   interface EventSource  Handler installHandler(Event event Handler newHandler);    客户代码如下   class EventSourceExample  public void example(Event event Handler newHandler)  oldHandler = eventSource installHandler(event newHandler);    private EventSource eventSource;  private Handler oldHandler;          这样 我们给调用者提供了一个更加安全的接口 并且不再需要他们解决线程的问题 从而降低了风险和代码量 将类设计的职责全部给了类设计者而不是推给用户 即使有代理对象的出现也不会影响到正确性     一个Combined Method可以是许多Query的集合 许多Command的集合 或者两者兼有 这样 它可能补充Command Query方法 也可能与之相抵触 当冲突发生的时候 优先选择Combined Method会产生一个不同的正确性和适用性     在另一个例子中 我们考虑获得资源的情况 假设 在下面的接口中 方法acquire在资源可用前阻塞   interface Resource  boolean isAcquired();  void acquire();  void release();          类似于下面的代码会在一个线程系统中推荐使用   class ResourceExample  public void example()  bool cha138/Article/program/Java/hx/201311/26294

相关参考

一般调压站的进出口管道上需装上绝缘接口,其作用

一般调压站的进出口管道上需装上绝缘接口,其作用。A.隔绝外来之导电装置B.作放进电子检查器的引入口C.用作站内管道的气密测试【参考答案】A[拓展知识]在选择合适大小的调压器时,设计最小流量一般以什么计

知识大全 Java 接口的异常设计疑惑

Java接口的异常设计疑惑  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  疑惑在设计接口的时对于

电力工程计算机辅助设计非图形信息的接口设计?

1设置互提资料库,规定各方享有的权限;  2列表说明接口的内容、数据类型、产生和使用地点、交接地点和交接方式,以及相应软件的运行环境;  3提供良好的用户接口。

电力工程计算机辅助设计非图形信息的接口设计?

1设置互提资料库,规定各方享有的权限;  2列表说明接口的内容、数据类型、产生和使用地点、交接地点和交接方式,以及相应软件的运行环境;  3提供良好的用户接口。

怎样选购客厅的灯具? 家庭装修客厅选择水晶吊灯合适吗?

水晶吊灯并不适合所有的客厅.不妨提前了解客厅灯具选择技巧。小编认为灯具在整个家装过程中占有非常重要的地位,好的室内灯具设计与安装能给整个家居装饰效果增加不少温馨分数。但是室内灯具在搭配过程中并不是随便

知识大全 电视没有hdmi接口怎样与手机连接

电视没有hdmi接口怎样与手机连接手机没有hdmi接口,不能接电视机hdmi接口。如果需要将手机的画面传输到电视机上,可以采用以下2种办法:1/如果电视机有蓝牙功能,可以直接通过蓝牙,将手机与电视机连

知识大全 我家的电视没有HDMI接口也没有VGA,接口看了一下,只有什么USB接口要怎样才能和笔记本电脑连接

我家的电视没有HDMI接口也没有VGA,接口看了一下,只有什么USB接口要怎样才能和笔记本电脑连接  以下文字资料是由(本站网www.cha138.com)小编为大家搜集

知识大全 怎样看自己的主板sata接口类型

怎样看自己的主板sata接口类型在系统下运行Everest,检测系统硬件,如果sata口测试是3GB的,就是sata2,如果是6GB的,就是sata3.这样测试的比较准确。接口类型为SATA的光驱可以

落地窗要不要安装护栏?按规定装多高合适呢?怎样焊接牢固呢?

关键词:落地窗护栏焊接危害程度:极大,危及生命安全返工难度:不大是否必须现场监工:务必现场监工如今,越来越多的住宅楼房都设计了美观大方的落地窗,采光好、观景效果好、充满了时代气息。虽然开发商为落地窗安

防盗安全门怎样进行紧急开启接口试验?

  输入三次错误密码,检查是否产生报警状态;在报警期间输入专用程序及正确电子密码,检查电子密码锁的开启情况,人为制造电子密码锁出现电路故障而失效,检查电子密码锁紧急开启接口的功能。  试验结果应符合以