`
calmness
  • 浏览: 353308 次
  • 性别: Icon_minigender_1
  • 来自: 珠海
社区版块
存档分类
最新评论

关于接口暴露问题的解决思路

    博客分类:
  • Java
阅读更多
前一两天在讨论群里,我提出过一个关于接口暴露的问题与群友们进行讨论,后来无甚结果,所以把自己这一问题在这里提出来,希望和大家讨论讨论。

   该问题主要是关于对外接口暴露的问题(此接口并非指java中的interface,而是指用户编程时可使用的接口),例如有一个类的大部分方法是不应该暴露给用户的,然而事实上,因为设计问题,任何一个用户都可以创建该类的实例以至于使用它,虽然在实际当中,可能没有用户会去这样做,不过我认为如果能够尽量避免这种情况应该是最好的选择。但是又该如何避免呢?

   我想这种问题出现的主要原因体现在设计者在对象职责分配上想尽可能的达到分散职责让程序更容易进行维护,这种目的是非常正确的,不过在实现上可能没有注意到接口暴露的问题,导致出现了我所说的情况。在群中讨论的时候,并没有人认同我的看法,也许我是错的,也许我是对的,不过这无关紧要,重要的是能够通过交流发现问题促进进步。

举个简单的例子:

public class TestA{
 public void methodA(){
   TestB testB = new TestB();
   testB.methodB();
}
} 

public class TestB{
 public void methodB(){
……
}
} 


在上面这个例子中,TestA依赖于TestB,而TestB这个类的方法应该是用户不可见,且不能让用户使用的,如果按照上面的方法,用户就可以使用TestB这个类了。

   对于这一问题,我的解决办法是将职责分配到实现类的父类或者接口上,在实现类当中以protected为方法标识,这样做虽然不能完全避免,但是可以尽可能的让客户知道哪些是给他使用哪些是不该使用的。

public class TestA extends TestB{
 public void methodA(){
   methodB();
}
}
public class TestB{
 protected void methodB(){
……
}
}


根据上面这种方式,TestB的方法通过protected进行了隐藏,可以进一步的让用户得知他所拥有的权限,从而就可以很轻易的解决了接口暴露的问题,上面的例子只是为了表达明确,并没有过多的设计,在实际开发当中,TestB更多的是作为抽象类或者是接口的形式出现,这种做法一样达到了对象职责的区分,容易维护,同时也封装了不该外露的接口,而且也可以随时开发给用户使用。在这里我只讲了一个大概的思路,并没有详细讨论如何去做,还需大家一起来参与。

对于这一问题只是本人一家之谈,可能有很多我没有想过的问题,有不同意的朋友欢迎与我讨论。
分享到:
评论
9 楼 intolong 2007-04-25  
感觉接口通常有两种:

1. 客户接口,主要暴露给客户,供客户方便使用。

2. 实现接口,真正用于实现代码的地方,可供其实现者,客户接口实现者(用来组装)和高级用户使用。

客户接口通常要客户用最小的努力使用到尽可能常用的功能,它的实现一般会去assemble各种实现接口的实现类,所以它很象一个facade.

实现接口才是真正用来封装,复用的。通常实现接口的实现类都写的短小精悍,做最少的事情,把组装的工作留给别人(客户接口实现类)。
8 楼 daynight830 2007-04-24  
其实design patterns就是为了解决一系列的这些问题。客户端所有的调用都应该通过调用接口来完成,虽然new了不同的实现子类,但是子类的具体实现,客户端是无法看到的。所以楼主的大体思想是对的,我表示赞同。
7 楼 海妖的夜 2007-04-22  
或许可以使用private的默认构造方法.那么B类最好不要有默认构造函数要做的事情,或者把初始化挪到init方法里去,或者有参数的构造方法,让别人来调.如果说a也打算用有参数的构造方法的话,那狠一点都放到init里做初始化好了.
主要目的是告诉别人如果你new了我,那么我就报错,你就无法使用我,你要用我就必须换一种方法来创建我.
结合factory的话,应该就更加可行了.
另外我也觉得你如果这么new的话,有必要放到一个包里面.
另外提出我的一个方法:
权限都用包权限,然后要对外开发的东西就用一个代理类公布出去,要调就调代理类好了.去除a和b的耦合比较好.
6 楼 weiqingfei 2007-04-22  
calmness 写道


引用

既然TestB只对TestA开放,那么说明两个类的紧密性,那么把这两个类放到一个包里,让方法使用默认修饰,只在本包内使用就可以了。

使用默认修饰并不好,这样就迫使依赖该类方法的其他类必须与该类在同一个包内,导致包可能非常臃肿,这种方式是最不推荐的了


如果两个类有这样的特殊关系,没有理由不把他们放在同一个包里,如果这样包就出现了臃肿问题,那只能说明设计上有问题。
5 楼 歆渊 2007-04-20  
这是个有意义的问题, 像C++就有一个 friend 关键字, 用来给特殊关系的类之间开后门. 到了 Java 把这个给去掉了, 我觉得不是因为这个机制完全没有必要, 而是 friend 修饰这么单一级别的划分对实质性问题反而欲盖弥彰, 还不如不要. Java 里似乎是通过默认的 default/package 权限来解决这方面的问题, 同一个包里的类可以互相之间访问任何非private的成员.

不过OO再精练升华以后, 我相信下一代OO语言在这个方向上还是需要点作为的. 可能是在 "代码单元" 之间可以自定义角色, 比如Helper, Client之类的, 根据角色再进一步界定不同成员的访问权限/可见性.
4 楼 calmness 2007-04-20  
引用

从设计的角度来将,应该暴露只应该暴露的东西,但是楼主的例子还是有些问题,因为如果是classB完全只被classA使用,则完全可以将B作为A的内部类来使用,我们永远不要忘记优先使用聚合的原则。

毕竟继承让我们浪费了一次继承的机会。

实际上这里涉及到两个问题,类隐藏和方法隐藏。

关于类的隐藏可以设计成内部类,前提是只有一个类引用,也就是说该类是私有的。另外可以通过factory的作用达到隐藏具体类创建的作用。
当然如果调用者绕过Factory非要new XXImpl出来则也没有办法。

方法隐藏就是对于public方法的定义要小心,确认是否真正的需要public。

对于设计我觉得定义方法的公开级别比类更加普遍。

可能是我的表达有问题,我所指的情况是在TestB并不仅仅只给A使用的情况下,如果使用内部类隐藏则把整个类都隐藏了,不适合其他类使用,对于使用factory来进行隐藏,可是类仍然存在可被直接使用的问题,能尽量不提供公共的接口就应该避免,当然是在可行的情况下,而非是什么情况都使用继承或者接口实现来处理这一问题。

引用

例子好像有点不合适
classB要让classA用 就已经暴露接口了 。

我所谓的暴露接口是指避免让用户可以直接使用,而classA是必须依赖于B的,但是B则不能够提供给其他人使用

引用

既然TestB只对TestA开放,那么说明两个类的紧密性,那么把这两个类放到一个包里,让方法使用默认修饰,只在本包内使用就可以了。

使用默认修饰并不好,这样就迫使依赖该类方法的其他类必须与该类在同一个包内,导致包可能非常臃肿,这种方式是最不推荐的了
3 楼 weiqingfei 2007-04-20  
既然TestB只对TestA开放,那么说明两个类的紧密性,那么把这两个类放到一个包里,让方法使用默认修饰,只在本包内使用就可以了。
2 楼 xly_971223 2007-04-20  
例子好像有点不合适
classB要让classA用 就已经暴露接口了 。
1 楼 jamesby 2007-04-20  
从设计的角度来将,应该暴露只应该暴露的东西,但是楼主的例子还是有些问题,因为如果是classB完全只被classA使用,则完全可以将B作为A的内部类来使用,我们永远不要忘记优先使用聚合的原则。

毕竟继承让我们浪费了一次继承的机会。

实际上这里涉及到两个问题,类隐藏和方法隐藏。

关于类的隐藏可以设计成内部类,前提是只有一个类引用,也就是说该类是私有的。另外可以通过factory的作用达到隐藏具体类创建的作用。
当然如果调用者绕过Factory非要new XXImpl出来则也没有办法。

方法隐藏就是对于public方法的定义要小心,确认是否真正的需要public。

对于设计我觉得定义方法的公开级别比类更加普遍。

相关推荐

    java源码资源手机游戏J2ME毕业设计

    java源码资源手机游戏J2ME毕业设计提取方式是百度网盘分享地址

    第5章 存储器管理(笔记整理)

    内容概要:本章节深入探讨了存储器管理和相关概念。首先介绍了存储器的多层次结构,涵盖了寄存器、主存和辅助存储的区别及其功能。接下来讨论了主存储器、寄存器的功能和角色,包括二者如何支持程序运行及数据处理。之后分析了高速缓存和磁盘缓存的运作机制及其优化计算机性能的方式。接着概述了程序的装入、链接、地址绑定、内存保护的技术细节。此外,文章还讲述了存储器管理的高级技巧如对换技术、覆盖技术和不同的分配方式,以及各种存储管理模式的具体实施方式,比如连续分配、分页、分段及段页组合。 适用人群:对操作系统内部工作原理有一定兴趣的计算机专业学生、技术人员及爱好者。 使用场景及目标:适用于课程学习和项目实践中,帮助理解和设计复杂的存储管理系统。通过本文的学习可以达到对操作系统底层存储管理的理解,掌握不同存储分配策略的选择标准和技术应用。 阅读建议:建议逐步阅读每个小节,重点关注各部分内容的实际应用场景及其背后的设计理念。同时,尝试绘制存储层次模型和不同管理策略的工作流程图,加深理解。

    gradle611all.zip.png

    gradle611all.zip.png

    onnxruntime-1.16.0-cp39-cp39-win_amd64.whl

    onnxruntime-1.16.0-cp39-cp39-win_amd64.whl

    C#ASP.NET大型商城系统源码带数据库文档数据库 SQL2008源码类型 WebForm

    ASP.NET大型商城系统源码带数据库文档 1.开发环境:vs2010 + slq2005/2008 2.首先在SQL2005建立一个空白数据库。 3.有VS2010 打开项目,直接调试,根据出现提示建立数据库。 4.第3点出现的页面的管理员用户和密码就是后期软件的登陆帐户和密码。 5.本系统有两套模版,在店铺管理 - 页面设置 这里做修改 6.如果觉得自己的系统是空数据库,想弄成和演示的一样,那就将doc/database下面的数据库直接还原就可以了。 7.还原后的数据库登陆帐户和密码分别是:admin888 admin888

    C#ASP.NET酒店管理系统源码(WPF)数据库 Access源码类型 WinForm

    ASP.NET酒店管理系统源码(WPF) 一、源码特点 采用WPF进行开发的酒店管理系统源码,界面相当美观,功能齐全 二、菜单功能 1、预订登记:可选择入住时间、离店时间、所在城市、证件类型,保存、删除、查询、返回 2、住宿结算:新增入住、保存、删除、查询、返回 3、今日盘点:查询、返回 4、查询统计: 5、房间管理:增加房间类型、删除类型、增加房间、删除房间、保存、返回 6、用户管理:增加用户、删除用户、保存、返回 7、系统配置:基本功能 8、显示当前系统时间等功能的实现

    资源quazip.dll

    资源quazip.dll

    C#汽车货运管理系统源码 货运公司车辆管理系统源码数据库 SQL2008源码类型 WinForm

    汽车货运管理系统源码 货运公司车辆管理系统源码 货运公司管理系统采用winform C# 技术开发,数据库Sqlserver2008R2,同时兼容Mysql。 更新日志: 1.修改新增数据异常。 2.增加安装部署工程。 包括如下功能模块: 一、输入功能: 该系统提供了对基本信息录入、车辆登记录入、车辆各项费用录入、驾驶员登记录入、车辆出回车录入、主卡分卡充值录入、加油登记录入,配件信息录入等的模式录入和表格界面录入。在出现从表信息录入时会出现表格界面的录入方式其录入方式同模式录入方式一样。录入信息时可能会出现相同的信息,为避免重复录入部分字段设置了辅助录入功能,您只需输入几项即可完成录入功能。操作方便快捷,可大大提高您的工作效率。 二、查询功能: 您只需用鼠标点击一下相应节点,就可迅速查询统计销售的情况,根据不同的查询统计条件显示出需要的结果。 三、报表功能: 根据查询或者统计出来的结果生成报表。 四:打印功能: 系统支持打印功能,如想打印信息单击预览报表上的打印按钮即可。 五、安全功能: 进入系统后,单击菜单“系统→工具→用户及权限”可以设置系统的各用

    基于springboot+vue的大学生创业项目的信息管理系统源码数据库文档.zip

    基于springboot+vue的大学生创业项目的信息管理系统源码数据库文档.zip

    numpy-1.25.2-cp311-cp311-linux_armv7l.whl

    numpy-1.25.2-cp311-cp311-linux_armv7l.whl

    STM32神舟III号例程源码SD读卡器(神舟III号-库函数版)

    STM32神舟III号例程源码SD读卡器(神舟III号-库函数版)提取方式是百度网盘分享地址

    numpy-1.20.0-cp37-cp37m-linux_armv7l.whl

    numpy-1.20.0-cp37-cp37m-linux_armv7l.whl

    matplotlib-3.7.5-cp39-cp39-linux_armv7l.whl

    matplotlib-3.7.5-cp39-cp39-linux_armv7l.whl

    onnxruntime-1.16.3-cp38-cp38-win_amd64.whl

    onnxruntime-1.16.3-cp38-cp38-win_amd64.whl

    【node毕业设计】nodejs学院会议纪要管理系统源码(完整前后端+mysql+说明文档).zip

    环境说明: 开发语言:nodejs 框架:Express 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:VS code/HBuilder X

    【小程序毕业设计】自助购药小程序源码(完整前后端+mysql+说明文档+LW).zip

    功能说明: 系统主要包括首页、个人中心、用户管理、商家管理、药品信息管理、药品分类管理、发票信息管理、系统管理等功能模块。 环境说明: 开发语言:Java 服务器:tomcat7及以上 JDK版本:JDK1.8 数据库:mysql 5.7数据库工具:Navicat11及以上 开发软件:eclipse/idea 小程序框架:uniapp/原生小程序 开发工具:HBuilder X/微信开发者

    基于Servlet和JSP实现的登录Demo

    《基于Servlet和JSP实现的登录Demo》项目是一个简单的 Java Web 应用示例,展示了如何使用 Servlet 和 JSP 搭建基础的用户登录功能。项目通过 Java Servlet 处理用户请求,使用 JSP 构建前端页面,并结合 MySQL 数据库验证用户身份。用户可以通过登录页面提交账号和密码,后端接口会对用户输入进行校验,并返回登录结果。本项目适合 Java Web 初学者,旨在帮助学习 Servlet 和 JSP 的基础用法,掌握表单提交、请求转发、数据库连接等关键技术点。项目环境包括 IntelliJ IDEA、Apache Tomcat 和 MySQL,支持 JDK 8 及以上版本。

    (全新整理)中国高校各专业录取分数线、招生计划、分段表数据(2008-2023年)

    1、资源内容地址:https://blog.csdn.net/2301_79696294/article/details/143733939 2、数据特点:今年全新,手工精心整理,放心引用,数据来自权威,且标注《数据来源》,相对于其他人的控制变量数据准确很多,适合写论文做实证用 ,不会出现数据造假问题 3、适用对象:大学生,本科生,研究生小白可用,容易上手!!! 4、课程引用: 经济学,地理学,城市规划与城市研究,公共政策与管理,社会学,商业与管理

    pillow-10.3.0-cp39-cp39-linux_armv7l.whl

    pillow-10.3.0-cp39-cp39-linux_armv7l.whl

    opencv_contrib_python-4.5.1.48-cp39-cp39-linux_armv7l.whl

    opencv_contrib_python-4.5.1.48-cp39-cp39-linux_armv7l.whl

Global site tag (gtag.js) - Google Analytics