我认为关键的洞察力是凝聚力。在您的描述中,您混合了应用程序的非常不同的方面。即,您将用户交互(我想要用户..)与查找特定信息的低级机械细节混合在一起。
OSGi 的基本思想是将这些部分分离为服务。该服务提供了一个高度内聚的低级功能。即它只做一件事,而且只做一件事。如果您查看事件管理服务,您会看到它确实发布和订阅。这个想法是,您最终会得到不同的服务,它们可以很好地完成一件事,并且与任何其他服务都没有关系(或耦合)。这种策略允许它们在许多不同的应用程序中重复使用。一旦你让凝聚力下降,你会发现它们变得更难在其他应用程序中重用。这听起来比实际上容易,通常需要一些迭代才能获得真正有凝聚力的服务。
组件是可以提供服务的 OSGi 事物。通常,组件会消耗其他服务。在您的示例中,您可以有一个包含城市的数据库。为了保持组件的内聚性,它不应该直接操作数据库,而是使用服务。您的组件应该只是城市方面的专家,但对数据库的东西一无所知。每当您编写组件并意识到您正在编写与城市无关的代码时,请将其委托给另一个服务。还要确保您的数据库服务对城市一无所知,它只知道数据库。城市组件有一种非常简单的方法,可以从一个对城市一无所知的组件访问其城市。
如果你这样想,你最终会得到很多什么都不做的服务。您需要在某个地方协调这些服务。这是应用程序。应用程序负责整体功能。它的目的是将所有松散的末端绑在一起。在您的情况下,它将消耗城市、天气和其他服务。它还将与用户交互。为了与用户交互,它需要能够搜索城市。所以像这样的服务接口会很有用:
public interface Geo {
List<String> countries();
List<String> cities(String country);
Country city(String country);
City city(String city);
}
我正在结合您的城市和国家查找器,因为我发现它们非常有凝聚力。将它们分解会增加复杂性。该服务允许我在国家/地区的用户界面上创建一个弹出窗口,并且从选定的国家/地区中,我可以选择一个城市。
接下来是气象服务:
public interface Weather {
boolean hasWeather( String country, String city);
Report getShortReport(String country, String city);
}
选择国家和城市后,我可以向气象服务部门索取报告。
我在这些接口中使用 String 的原因是为了防止 Geo 服务和 Weather 服务之间的耦合。这是我经常看到的主要菜鸟错误之一。创建 City & Country 类型,然后在所有地方使用(或更糟糕的是,CityKey),有效地使系统再次成为一个大泥球,其中所有内容都通过一些仅充当字符串的类与其他所有内容相关联。
因此,现在应用程序组件可以选择一个 GUI(HTML、gogo、Swing、SWT 等)。它可以有效地专注于 GUI,而底层细节由服务提供者处理。应用程序通常应该是系统中唯一不能被任何人重用的组件。如果是,请将其拆分为可重用部分和特定部分。由于该组件不可重用,因此它是您软件中唯一不必关心耦合的地方。
概括。这个想法是,如果您查看 OGSi 应用程序的服务图,它应该清楚地知道事情发生在哪里,并且应用程序组件(通常不是服务本身)将它们联系在一起。
希望这可以帮助。