返回顶部
首页 > 资讯 > 精选 >JAVA中如何设计合适的接口
  • 869
分享到

JAVA中如何设计合适的接口

2023-06-03 05:06:05 869人浏览 安东尼
摘要

这篇文章主要介绍JAVA中如何设计合适的接口,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!我们在设计系统接口时,经常会遇到这样的问题:我们的接口应该提供多少方法才合适?我们的接口应该提供"原子方法"

这篇文章主要介绍JAVA中如何设计合适的接口,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

我们在设计系统接口时,经常会遇到这样的问题:

我们的接口应该提供多少方法才合适?

我们的接口应该提供"原子方法"还是"复合方法"?

我们的接口是否应该封装(或者,能否封装)所有的细节?

接口的设计需要考虑用户的使用习惯、使用的方便程度、使用的安全程度,根据我的编程经验,下面会详细讨论接口设计的2个需要权衡的方面:接口的单一化 & 复合化。


接口

接口提供了不同系统之间或者系统不同组件之间的界定。在软件中,接口提供了一个屏障,从而从实现中分离目标,从具体中分离抽象,从作者中分离用户。

站在用户的角度看,一个接口建立并命名了一个目标对象的使用方法。一些约束(例如:编译时的类型系统、运行时的异常机制及返回值)使得类作者的目的得以体现和加强。供给(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 = collection.iterator();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域引用一个线程共享的对象,对象很可能在1、2之间被另一个线程安装了一个新的句柄:

class EventSourceExample{public void example(Event event, Handler newHandler){oldHandler = eventSource.getHandler(event); // 1//对象很可能在这里被另一个线程安装了一个新的句柄eventSource.installHandler(event, newHandler); // 2}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(){boolean acquired = false;synchronized(resource){if(!resource.isAcquired())resource.acquire();elseacquired = true;}if(!acquired)...}private Resource resource;}

然而,即使我们放弃可读性和易用性,这样的设计也不是一个Command-Query分离的设计。如果引入了代理,它就会失败:

class ActualResource implements Resource {...}class ResourceProxy implements Resource {...}

如果用户既可以通过ActualResource来完成工作,也可以通过ResourceProxy来完成工作,而且,ActualResource和ResourceProxy都没有处理同步,则synchronized块可能会失败。因为,既然我们可以通过代理对象ResourceProxy来完成工作,那么,调用者的synchronized块,同步的就是代理对象ResourceProxy而不是最终的目标对象ActualResource。

一个Combined Method解决了这个问题,它使并发和间接性更加透明。

interface Resource{

boolean tryAcquire();

}

下面的代码清晰、简单并且正确:

class ResourceExample{public void example(){if(!resource.tryAcquire())...}private Resource resource;}

Combined Method带来的一个结果是使一些测试和基于断言的程序设计变得十分笨拙,然而,它适合解决线程和分布问题。

实际应用中,接口应该单一化还是复合化,要视具体情况而定。

以上是“JAVA中如何设计合适的接口”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: JAVA中如何设计合适的接口

本文链接: https://lsjlt.com/news/232885.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • JAVA中如何设计合适的接口
    这篇文章主要介绍JAVA中如何设计合适的接口,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!我们在设计系统接口时,经常会遇到这样的问题:我们的接口应该提供多少方法才合适?我们的接口应该提供"原子方法"...
    99+
    2023-06-03
  • 如何选择最合适的 PHP 设计模式
    选择最合适的 php 设计模式分为以下 5 个步骤:识别问题研究设计模式理解模式应用模式实战案例 如何选择最合适的 PHP 设计模式 设计模式是经过验证的、可重复使用的解决方案,用于解...
    99+
    2024-05-07
    php 设计模式
  • PHP和Git如何结合使用来优化接口设计?
    在现代软件开发中,版本控制是一项至关重要的工作。它不仅可以让开发者更好地管理代码,还可以更好地追踪代码的历史变化、方便地协作开发、以及更方便地发布软件版本。Git作为目前最流行的版本控制工具之一,已经被广泛应用于各种软件开发中。 而对于P...
    99+
    2023-10-11
    git 接口 自然语言处理
  • 如何选择合适的嵌入式设计软件
    这篇文章主要介绍了如何选择合适的嵌入式设计软件,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、设备/内核支持在选择嵌入式设计软件时,你首先需要考虑的你所选择的软件对你所选择...
    99+
    2023-06-17
  • PHP设计模式:如何选择适合的模式
    在 php 中选择设计模式的步骤:识别问题研究设计模式匹配模式到问题实施模式通过这些步骤,可以根据具体情况选择合适的设计模式,从而提高代码质量、灵活性性和可维护性。 PHP 设计模式:...
    99+
    2024-05-13
    php 设计模式 mysql 数据访问
  • 如何在GO语言中优化接口设计?
    Go是一种高效且易于使用的编程语言,它的优势在于其简单的语法和强大的并发特性。在设计接口时,Go语言提供了一些有用的工具和技巧,可以帮助我们创建出高效且易于维护的接口。 下面是一些关于如何在Go语言中优化接口设计的建议: 使用接口而不是...
    99+
    2023-06-15
    自然语言处理 打包 接口
  • Git是如何影响PHP接口设计的?
    随着软件开发的不断发展,Git已经成为了现代软件开发中必不可少的工具之一。Git的出现为开发人员提供了更加高效、灵活、可靠的代码管理方式,同时也改变了软件开发的模式和流程。在PHP接口设计方面,Git也对开发人员带来了很大的影响。 Git...
    99+
    2023-10-11
    git 接口 自然语言处理
  • Python 异步编程框架中,如何选择最适合你的接口?
    随着互联网技术的不断发展,异步编程已经成为了一种必备的技能。Python作为一门高效、易学易用的编程语言,自然也不例外。Python中有许多异步编程框架,比如 asyncio、aiohttp、tornado、Twisted等等。那么在这么...
    99+
    2023-06-27
    异步编程 框架 接口
  • 设计java中的接口需要遵循哪些原则
    设计java接口的规范性建议:1.职责原则在设计接口时,必须明确接口的职责,即接口类型,接口应解决什么业务问题等2.单一性原则在明确接口职责的条件下,尽量做到接口单一,即一个接口只做一件事,而非两件以上。很多非资深接口设计者,在设计接口时,...
    99+
    2016-11-03
    设计 java 接口 原则
  • 如何在响应式设计中选择最适合的布局方式
    在当今互联网时代,移动设备的普及率越来越高,用户对于访问网页的需求也开始从传统的桌面电脑转向移动设备,这就使得网页设计师需要考虑响应式设计来适应不同屏幕尺寸的设备。而在响应式设计中,选...
    99+
    2024-02-22
    适合:适合 响应式设计:响应 布局方式:布局 弹性布局
  • 接口类型选择指南: 如何根据需求选择适合的接口类型
    接口类型选择指南: 如何根据需求选择适合的接口类型,需要具体代码示例导言:在开发软件中,接口是不可或缺的组成部分。选择适合的接口类型对于软件的功能和性能是至关重要的。本文将介绍几种常见的接口类型,并提供代码示例,帮助读者根据实际需求进行选择...
    99+
    2023-12-23
    接口类型 需求分析 接口选择
  • Java设计模式中的适配器模式
    目录基本介绍工作原理类适配器模式对象适配器模式接口适配器模式适配器模式的注意事项和细节基本介绍 适配器模式(Adapter Pattern)将某个类的接口转换成客户端期望的另一个接口...
    99+
    2024-04-02
  • java中如何实现接口
    接口的实现格式:[修饰符] class [extends 父类名] [implements 接口列表]{ }修饰符:可选参数,用于指定类的访问权限,可选值为public、abstract和final。类名:必选参数,用于指定类的名称,类名...
    99+
    2020-03-10
    java入门 java 接口 实现
  • java中如何定义接口
    这期内容当中小编将会给大家带来有关java中如何定义接口,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式...
    99+
    2023-06-14
  • Java中如何实施接口
    这篇文章主要介绍了Java中如何实施接口,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在封装与接口中,private关键字封装了对象的内部成员。经过封装,产品隐藏了内部细节,...
    99+
    2023-06-02
  • 如何设计一个安全的API接口详解
    目录前言一 安全性问题 1.1 调用接口的先决条件-token 1.2 使用POST作为接口请求方式 1.3 客户端IP白名单 1.4 单个接口针对ip限流 1.5 记录接口请求日志...
    99+
    2024-04-02
  • Java集合的Collection接口和List接口详解
    目录1集合的概念2 集合的父类Collection接口2.1常用方法2.2遍历 3 List接口3.1List接口常用方法3.2遍历4 集合中元素的去重总结1集合的概念 把...
    99+
    2024-04-02
  • PHP 和 Django:如何选择最适合你的接口开发框架?
    在接口开发中,选择一个适合自己的框架可以大大提高开发效率,同时也会使代码更加可维护和可扩展。PHP 和 Django 都是比较流行的接口开发框架,那么如何选择最适合自己的框架呢? PHP PHP 是一种广泛应用于 Web 开发的脚本语...
    99+
    2023-06-13
    django 并发 接口
  • 如何选择一款适合大数据接口开发的 PHP IDE?
    随着大数据技术的不断发展,越来越多的企业和组织开始将大数据技术应用于业务场景中。而作为大数据技术的基础,数据接口的开发显得尤为重要。PHP 作为一门流行的 Web 开发语言,也在大数据应用中扮演着重要的角色。本篇文章将介绍如何选择一款适合大...
    99+
    2023-10-07
    ide 接口 大数据
  • PHP 并发编程的 IDE 工具:如何选择适合你的接口?
    在现代 Web 应用程序中,并发编程已经成为了一个非常重要的话题。PHP 作为一种流行的 Web 编程语言,也开始越来越多地涉及到并发编程。而为了更好地进行 PHP 并发编程,选择一个合适的 IDE 工具是非常重要的。 在本文中,我们将介...
    99+
    2023-06-08
    并发 ide 接口
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作