我目前工作的地方我使用一个单独的类来改变用户的视图的项目。 这DISPLAYMANAGER(单身)具有类似的方法addView(View view)
和replaceView(View view)
。 但它也有一个称为方法displayRootView()
其可仅被调用一次(INIT期间),并通过只有1类,即扩展了应用类的启动类。
任何想法,我怎么能阻止谁使用来自调用单身其他类displayRootView()
方法?
我已经考虑堆栈跟踪,但似乎并不理想。 我虽然可能通过使用启动类的标记接口,以使其与其他单独的呢?
任何建议将不胜感激。
呃,这是难以避免调用您的方法中的某些类,因为它打破了一些核心的原则OOP。 该方法不应该关心谁调用它。 这是关注基本分离 - 你的方法有关于它做什么,不是什么是当时的JVM的状态的明确合同。
考虑下列问题:
- 如果你继承会发生什么
StartUp
? 例如分离桌面,移动和网络平台? - 你单位将如何测试不涉及这种方法
StartUp
? - 如果你需要的抽象存在的另一层会发生什么?
- 那么如果当你添加代理服务器(通过AOP或Spring代理)?
- 如果你需要调用从该方法会发生什么
Timer
? 它仍然打算从所谓的StartUp
类源(和是正确的),但它不会出现在堆栈跟踪。
和其他类似的考虑。
抛出某种异常(例如IllegalStateException
,或者自定义),如果该方法被称为第二次是绝对有效恕我直言。
这看起来像你可能想在你的代码的静态检查 ,而不是在代码或运行时检查。 我不认为这将是非常困难添加自定义规则Findbugz或PMD找到一个方法的所有直接调用和查询调用类(如果它是从其他地方调用构建失败)。 但是,我不认为这样的检查是真正有用的。
最后,也有很多,你需要方法的合法使用上述类外,比有有人会不小心使用不当,他们已经被警告和适当的Javadoc创建后的机会。
的JavaFX应用程序源确实通过解析堆一些时髦的东西迹线,以确定并检查主叫方(例如,以确保它是仅由延伸的应用类的称呼)。
/**
* Launch a standalone application. This method is typically called
* from the main method(). It must not be called more than once or an
* exception will be thrown.
* This is equivalent to launch(TheClass.class, args) where TheClass is the
* immediately enclosing class of the method that called launch. It must
* be a subclass of Application or a RuntimeException will be thrown.
*
* <p>
* The launch method does not return until the application has exited,
* either via a call to Platform.exit or all of the application windows
* have been closed.
*
* <p>
* Typical usage is:
* <ul>
* <pre>
* public static void main(String[] args) {
* Application.launch(args);
* }
* </pre>
* </ul>
*
* @param args the command line arguments passed to the application.
* An application may get these parameters using the
* {@link #getParameters()} method.
*
* @throws IllegalStateException if this method is called more than once.
*/
public static void launch(String... args) {
// Figure out the right class to call
StackTraceElement[] cause = Thread.currentThread().getStackTrace();
boolean foundThisMethod = false;
String callingClassName = null;
for (StackTraceElement se : cause) {
// Skip entries until we get to the entry for this class
String className = se.getClassName();
String methodName = se.getMethodName();
if (foundThisMethod) {
callingClassName = className;
break;
} else if (Application.class.getName().equals(className)
&& "launch".equals(methodName)) {
foundThisMethod = true;
}
}
if (callingClassName == null) {
throw new RuntimeException("Error: unable to determine Application class");
}
try {
Class theClass = Class.forName(callingClassName, true,
Thread.currentThread().getContextClassLoader());
if (Application.class.isAssignableFrom(theClass)) {
Class<? extends Application> appClass = theClass;
LauncherImpl.launchApplication(appClass, args);
} else {
throw new RuntimeException("Error: " + theClass
+ " is not a subclass of javafx.application.Application");
}
} catch (RuntimeException ex) {
throw ex;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
该LauncherImpl代码使在一个私人静态的AtomicBoolean使用getAndSet操作,以确保应用程序没有启动一次以上。
// Ensure that launchApplication method is only called once
private static AtomicBoolean launchCalled = new AtomicBoolean(false);
/**
* This method is called by the standalone launcher.
* It must not be called more than once or an exception will be thrown.
*
* Note that it is always called on a thread other than the FX application
* thread, since that thread is only created at startup.
*
* @param appClass application class
* @param preloaderClass preloader class, may be null
* @param args command line arguments
*/
public static void launchApplication(final Class<? extends Application> appClass,
final Class<? extends Preloader> preloaderClass,
final String[] args) {
if (launchCalled.getAndSet(true)) {
throw new IllegalStateException("Application launch must not be called more than once");
}
if (! Application.class.isAssignableFrom(appClass)) {
throw new IllegalArgumentException("Error: " + appClass.getName()
+ " is not a subclass of javafx.application.Application");
}
if (preloaderClass != null && ! Preloader.class.isAssignableFrom(preloaderClass)) {
throw new IllegalArgumentException("Error: " + preloaderClass.getName()
+ " is not a subclass of javafx.application.Preloader");
}
// Create a new Launcher thread and then wait for that thread to finish
final CountDownLatch launchLatch = new CountDownLatch(1);
Thread launcherThread = new Thread(new Runnable() {
@Override public void run() {
try {
launchApplication1(appClass, preloaderClass, args);
} catch (RuntimeException rte) {
launchException = rte;
} catch (Exception ex) {
launchException =
new RuntimeException("Application launch exception", ex);
} catch (Error err) {
launchException =
new RuntimeException("Application launch error", err);
} finally {
launchLatch.countDown();
}
}
});
launcherThread.setName("JavaFX-Launcher");
launcherThread.start();
// Wait for FX launcher thread to finish before returning to user
try {
launchLatch.await();
} catch (InterruptedException ex) {
throw new RuntimeException("Unexpected exception: ", ex);
}
if (launchException != null) {
throw launchException;
}
}
因此,它是一种复杂的,怪异的,但如果你想有一个成熟的解决方案,适用于JavaFX的代码库,你可以尝试通过它来解析明白是怎么回事,它适应您的情况。
我只能说这引入额外的复杂应用程序,如果它是非常重要的东西为你的应用有。
Orodous使得如何阻塞性这样的逻辑可以是用于单元测试的一些优秀的点。 例如看看这个建议在部分的单元测试JavaFX应用程序 。 由于在发射怪异检查,独立测试他们的应用程序的功能,开发人员需要经过奇怪箍绕过调用任何发射代码(例如使用JavaFX基于JFXPanel而是因为所涉及的应用程序的一个Swing初始化应用程序只能使用一次推出)。
我会扔在displayRootView()被调用时不止一次一个IllegalStateException。
你可以考虑使用给出的“罗密欧与朱丽叶”伎俩在这里 ,原本在Java模拟(从C ++)的“朋友”的机制。