通过公共API导出非公共类型

2024-03-17

如果我有几个返回非公共类型的工厂方法和提供此非公共类型变量的配对方法集怎么办?这会导致 NetBeans 中出现标题为警告消息的结果。

结果公共 API 将只包含两个配对的方法集。原因是使我的类型层次结构密封(就像 Scala 中的密封类)并允许用户仅通过工厂方法实例化这些类型。所以我们在某种意义上得到了 DSL。

例如,由日历字段的约束表示的 Schedule 类。有一些类型的约束 - Range、Singleton、List、FullSet - 以 NumberSet 接口为根。我们不想公开这些类型以及 Schedule 如何与它们交互。我们只需要用户提供规格。因此我们将 NumberSet 设为包私有。在 Schedule 类中,我们为约束创建了一些工厂方法:

NumberSet singleton(int value);
NumberSet range(int form, int to);
NumberSet list(NumberSet ... components);

以及一些创建 Schedule 对象的方法:

Schedule everyHour(NumberSet minutes);
Schedule everyDay(NumberSet minutes, NumberSet hours);

用户只能通过以下方式使用它们:

Schedule s = Schedule.everyDay( singleton(0), list(range(10-15), singleton(8)) );

这是坏主意吗?


这个想法本身是合理的。但如果你这样做的话,这是行不通的根型 (here: NumberSet) 包私有。公开该类型或使用公共接口。实际的实现类型应该(并且可以)隐藏。

public abstract class NumberSet {

    // Constructor is package private, so no new classes can be derived from
    // this guy outside of its package.
    NumberSet() {
    }
}

public class Factories {

    public NumberSet range(int start, int length) {
        return new RangeNumberSet(start, length);
    }

    // ...
}

class RangeNumberSet extends NumberSet {
   // ... must be defined in the same package as NumberSet
   // Is "invisible" to client code
}

Edit从公共 API 公开隐藏/私有根类型是一个错误。考虑以下场景:

package example;

class Bar {
    public void doSomething() {
            // ...
    }
}

public class Foo {

    public Bar newBar() {
        return new Bar();
    }
}

并考虑使用此 API 的客户端应用程序。客户可以做什么?它无法正确声明变量具有类型Bar因为该类型对于包外的任何类都是不可见的example。它甚至不能调用public上的方法Bar它从某个地方获得实例,因为它不知道存在这样的公共方法(它看不到该类,更不用说它公开的任何成员了)。因此,客户在这里可以做的最好的事情是:

Object bar = foo.newBar();

这本质上是没有用的。另一件事是使用公共接口(或抽象类)而不是包私有接口,如上面定义的代码所示。在这种情况下,客户端实际上can声明一个变量类型NumberSet。它无法创建自己的实例或派生子类,因为构造函数对其隐藏,但它可以访问定义的公共 API。

再次编辑即使您想要一个“无特征”值(从客户端的角度来看),即一个没有定义客户端可能想要调用的任何有趣 API 的值,以这种方式公开公共基类型仍然是一个好主意如上所述。仅仅是为了编译器能够执行类型检查并允许客户端代码将这样的值临时存储到(正确声明的)变量中。

如果您不希望客户端调用该类型的任何 API 方法:那也可以。没有什么可以阻止您不在您的(否则)公共基类型上提供公共 API。只是不要声明任何。使用“空”抽象基类(从客户端的角度来看是空的,因为所有有趣的方法都是包私有的,因此是隐藏的)。但你仍然必须提供一个公共基础类型,或者你应该使用简单的Object作为返回值,但是您会在编译时放弃错误检查。

经验法则:如果客户端必须调用某个方法才能获取值并将其传递给其他 API,那么客户端实际上knows,有一些神奇的特殊值。它必须能够以某种方式处理它(至少“传递它”)。除了(完全适当的)编译器警告之外,不为客户端提供正确的类型来处理这些值不会给您带来任何好处。

public abstract class Specification {

    Specification() {
        // Package private, thus not accessible to the client
        // No subclassing possible
    }

    Stuff getInternalValue1() {
        // Package private, thus not accessible to the client
        // Client cannot call this
    }
}

就客户端代码而言,上面的类是“空”的;除了一些东西之外,它不提供可用的 API,Object已经优惠了。拥有它的主要好处是:客户端可以声明这种类型的变量,并且编译器能够进行类型检查。不过,您的框架仍然是唯一可以创建这种类型的具体实例的地方,因此,您的框架可以完全控制所有值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过公共API导出非公共类型 的相关文章

随机推荐

  • 不安装jre就运行java?

    正如所问和回答的here https stackoverflow com questions 2678702 install python 2 6 without using installer on win32 python 有一种无需安
  • 为什么在VS2010中添加服务引用时,没有生成客户端类?

    我快要疯了 我相信 也就是说 我以前从未遇到过这样的问题 而且似乎没有人 Google 已索引 遇到同样的问题 每当我向 VS2010 项目添加对特定 ASMX 服务的引用时 都会生成所有代码 并且有一个接口ServiceSoap它代表了服
  • 二维数组指针和 *arr[] 有什么区别?

    我试图理解这样的数组之间有什么区别 int arr 2 2 0 1 2 3 int pArr int arr for int i 0 i lt 4 i printf d pArr i 和这个 int foo 2 arr1 arr2 Let
  • null 和空字符串之间的区别[重复]

    这个问题在这里已经有答案了 空字符串 String s null 和一个空字符串 String s 这就是我所拥有的 String s1 print statement does not print any thing for s1 but
  • Haskell 如何创建 Word8?

    我想写一个简单的函数来分割ByteString into ByteString using n 作为分隔符 我的尝试 import Data ByteString listize ByteString gt ByteString listi
  • jQuery .ajax() 与 jsonp 不调用成功回调函数

    我有一个 facebook iframe 应用程序 它向我的服务器发出跨域请求并请求 JSONP 格式的数据 这是我的客户端代码 jQuery ajax url type post data method set user prizes d
  • 为什么 Python 不允许在其定义中引用类?

    Python 3 和 2 不允许您在其主体内引用类 方法中除外 class A static attribute A 这就提出了一个NameError在第二行 因为 A is not defined 而这 class A def metho
  • MPMoviePlayerViewController 无法在 iOS 7 上运行

    我有一个在 iOS 7 之前有效的代码 更新后电影无法播放 void setMovie NSURL newMovie autoPlay BOOL autoPlay movieView MPMoviePlayerViewController
  • 检测 JSplitPane 分隔线移动

    有没有办法检测 JSplitPane 分隔线何时移动 有没有办法为分隔线移动添加监听器 JPanel panel1 new JPanel JPanel panel2 new JPanel JSplitPane sp new JSplitPa
  • 如何在orders、ordersDetails模式中保存、处理订单总金额?

    几个月前 当我开始设计应用程序数据库模式时 我被告知不要存储相同的数据 计算数据数据库中的多个位置 规范化 如果我这样做 当我在一个地方更新数据而在另一个地方不更新时 我会产生一系列错误 所以我做了一个订单表和订单详细信息表 像这样的东西
  • XPath 适合 HTML5 格式吗?

    我们知道XPath是为XML解析而创建的 HTML5 怎么样 因为它不一定遵守 XML 规则 有 2 种 XML 词法 XML 和解析 XML XPath 针对解析的 XML 表示形式工作 例如 DOM 或XDM http www w3 o
  • 服务器发送 200:OK 时 Backbone model.save 返回错误

    我定义了以下骨干模型 var User Backbone Model extend url login contentType application com example auth json defaults userName pass
  • PHP中的while循环问题

    我的标记结构如下 div div value1 div div value2 div div value3 div div value4 div div class clear div div div div value5 div div
  • ASP.NET 2.0 网站可以引用 WCF Web 服务吗?

    我们公司目前有一个网站部署在Windows 2000操作系统中 这意味着我们只能在该机器上安装 NET 2 0 升级网络服务器操作系统是不可能的 因为该网络服务器还托管我们国家的其他网络应用程序 作为我们 IT 政策的一部分 出于安全原因
  • 在内容级别与 google chrome 扩展一起使用时,未定义 DP_jQuery_*

    我正在开发一个谷歌浏览器扩展 我正在尝试在现有网页 内容级别 的 jquery ui 对话框中使用 jquery ui datepicker 就像这样 截屏 http sites google com site kamimark files
  • 如何获取最近经过身份验证的用户?

    我正在使用 MVC 3 并且刚刚实现了 FormsAuthenticationService 的包装器 类似于以下内容 public void SignIn string username bool createPersistantCook
  • 小程序中的 java.lang.reflect.invocacytargetexception 错误 [已关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我的应用程
  • 在 mongoose 中使用 mongodb 多键索引方法索引引用数组

    我的架构有一个 ObjectId 数组 它们是对另一个架构的引用 我想要的是使用 mongodb 的多键索引方法来索引这个数组条目 所以给定一个ObjectId中的某些文档的产品目录集合 我可以列出我当前集合中具有给定的所有文档Object
  • 如何防止 VS2010 在每次更新服务引用时创建新绑定?

    我正在使用 C 3 5 和 Visual Studio 2010 中的 WCF 服务开发 Winforms 客户端应用程序 每次我使用 更新服务参考 在 IDE 中 考虑到我已经有一个有效的绑定app config 会生成一个具有相同名称和
  • 通过公共API导出非公共类型

    如果我有几个返回非公共类型的工厂方法和提供此非公共类型变量的配对方法集怎么办 这会导致 NetBeans 中出现标题为警告消息的结果 结果公共 API 将只包含两个配对的方法集 原因是使我的类型层次结构密封 就像 Scala 中的密封类 并