通过公共API导出非公开型 [英] Exporting non-public type through public API

查看:522
本文介绍了通过公共API导出非公开型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有几个工厂方法返回非公开型和配对的方法集合这给本次非公开类型的变量?这将导致与在NetBeans题为警告消息。

What if I have few factory methods returning non-public type and pairing set of methods which gives variables of this non-public type? This results with titled warning message in NetBeans.

在结果公开的API将仅包含两配对的方法集。原因是为了让我的类型层次密封(如在斯卡拉seald类),并允许用户只能通过工厂方法实例化这些类型。所以我们得到的DSL在某种意义上。

In result public API will contain only two pairing sets of methods. The reason is to make my type hierarchy sealed (like seald classes in Scala) and allow users only instantiate these types through factory methods. So we get DSL in some sense.

例如,计划再类$ P $按日历字段的约束上psented。有一些类型的约束上的 - 范围,辛格尔顿,列表,FullSet - 与NumberSet接口作为根。我们不希望公开这些类型及附表与之交互的方式。我们只是想从用户的规范。所以,我们做NumberSet包专用。在课堂上,我们计划建立几个工厂方法的限制:

For example, Schedule class represented by calendar fields' contraints. There are some types of contraints - Range, Singleton, List, FullSet - with NumberSet interface as a root. We don't want to expose these types and how Schedule interact with them. We just want the specification from the user. So we make NumberSet package-private. In class Schedule we create few factory-methods for constraints:

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

和一些方法来创建计划对象:

and some methods for creating Schedule object:

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

用户只能在方式使用它们:

User can only use them in the manner:

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

是不是坏主意?

推荐答案

这个想法本身是健全的。但它不会工作,如果你做的根型的(此处为: NumberSet )封装专用。无论是揭露该类型或使用一个公共接口来代替。实际实现类型应该(可以)被隐藏。

The idea itself is sound. But it won't work, if you make the root type (here: NumberSet) package private. Either expose that type or use a public interface instead. The actual implementation types should (and can) be hidden.

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
}

修改从公共API揭露隐藏/私有根型是一个错误。请考虑以下情形:

Edit To expose a hidden/private root type from a public API is a mistake. Consider the following scenario:

package example;

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

public class Foo {

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

和考虑使用此API客户端应用程序。有什么可以在客户端吗?它不能正确地声明一个变量有键入酒吧,因为该类型是不可见的任何类的包外例如。它甚至不能要求它从什么地方得到了酒吧实例公共方法,因为它不知道,这样的公共方法存在(它看不到类,更不用说它暴露的任何成员)。所以,最好的客户端可以在这里做的是一样的东西:

and consider a client application using this API. What can the client do? It cannot properly declare a variable to have type Bar since that type is invisible to any class outside of the package example. It cannot even call public methods on a Bar instance it got from somewhere, since it does not know, that such a public method exists (it cannot see the class, let alone any members it exposes). So, the best a client can do here is something like:

Object bar = foo.newBar();

这基本上是无用的。不同的事情是有一个公共接口(或抽象类),而不是包专用之一,在上面定义的code。在这种情况下,客户端实际的可以的声明类型的变量 NumberSet 。它不能创建自己的实例或派生子类,因为构造看不到它,但它可以访问公共API定义。

which is essentially useless. A different thing would be to have a public interface (or abstract class) instead of the package private one, as in the code defined above. In this case, the client actually can declare a variable of type NumberSet. It cannot create its own instances or derive subclasses, since the constructor is hidden from it, but it can access the public API defined.

再次编辑即使你想一个无特色值(从客户端的角度),即一个数值,它并没有定义任何有趣的API客户端可能需要调用,它仍然是一个好主意,以暴露在上述方式一公共基地类型。并只对编译器的目的是能够进行类型检查,并允许客户端code到这样的值暂时存储到(正确申报)变量。

Edit again Even if you want a "featureless" value (from the client's perspective), i.e., a value, which does not define any interesting APIs the client may want to call, it is still a good idea to expose a public base type in the way described above. And be it only for the purpose of the compiler being able to perform type checking and allowing client code to temporarily store such a value into a (properly declared) variable.

如果您不希望您的客户端调用的任何类型的API方法:这很好。没有什么$ P $从不提供有关您(否则)公共基类公共API pventing你。只是不声明任何。使用一个空抽象基类(从客户端的角度看空的,因为所有的有趣的方法是包专用,因此隐藏)。但是你必须提供尽管如此,公众基本类型,还是应该使用纯对象作为返回值,但你放弃错误在编译时检查。

If you don't want your client to call any API methods on the type: that's fine. There is nothing preventing you from not providing a public API on your (otherwise) public base type. Just don't declare any. Use an "empty" abstract base class (empty from the perspective of the client, since all interesting methods would be package private and thus hidden). But you have to supply a public base type nonetheless, or you should use plain Object as return value, but then you forfeit error checking at compile time.

经验法则:如果客户端调用一些方法,以获得一个价值传递给其他一些API,那么客户端实际的知道的,有一些神奇的特殊值。而且它必须能够处理它以某种方式(它传递,在非常至少)。客户端处理的值不会买你的,除了(完全适合)的编译器警告任何不提供正确的类型。

Rule of thumb: If the client has to call some method in order to obtain a value and pass it on to some other API, then the client actually knows, that there are some magic special values. And it has to be able to handle it in some way ("pass it on", at very least). Not providing a proper type for the client to deal with the values does not buy you anything except for (entirely appropriate) compiler warnings.

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
    }
}

以上类是空至于客户端code而言;它并没有提供的东西,除了一个可用的API,其中对象已经提供。有它的主要优点:客户可以声明这种类型的变量,编译器能够输入检查。你的框架,不过,仍然是唯一的地方,这种类型的具体实例可以被创建,因此,你的架构拥有所有值的总量控制。

The above class is "empty" as far as the client code is concerned; it does not offer an usable API except stuff, which the Object already offers. The major benefit of having it: the client can declare variables of this type, and the compiler is able to type check. Your framework, though, remains the only place, where concrete instances of this type can be created, and thus, your framework has total control over all values.

这篇关于通过公共API导出非公开型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆