我只是想知道:使用 Java 8,以及在接口中添加实现的可能性(有点像 Scala 特征),是否可以像在 Scala 中那样实现蛋糕模式?
如果是,有人可以提供代码片段吗?
我只是想知道:使用 Java 8,以及在接口中添加实现的可能性(有点像 Scala 特征),是否可以像在 Scala 中那样实现蛋糕模式?
如果是,有人可以提供代码片段吗?
在其他答案的启发下,我提出了以下(粗略的)类层次结构,类似于 Scala 中的蛋糕模式:
interface UserRepository {
String authenticate(String username, String password);
}
interface UserRepositoryComponent {
UserRepository getUserRepository();
}
interface UserServiceComponent extends UserRepositoryComponent {
default UserService getUserService() {
return new UserService(getUserRepository());
}
}
class UserService {
private final UserRepository repository;
UserService(UserRepository repository) {
this.repository = repository;
}
String authenticate(String username, String password) {
return repository.authenticate(username, password);
}
}
interface LocalUserRepositoryComponent extends UserRepositoryComponent {
default UserRepository getUserRepository() {
return new UserRepository() {
public String authenticate(String username, String password) {
return "LocalAuthed";
}
};
}
}
interface MongoUserRepositoryComponent extends UserRepositoryComponent {
default UserRepository getUserRepository() {
return new UserRepository() {
public String authenticate(String username, String password) {
return "MongoAuthed";
}
};
}
}
class LocalApp implements UserServiceComponent, LocalUserRepositoryComponent {}
class MongoApp implements UserServiceComponent, MongoUserRepositoryComponent {}
截至 2013 年 1 月 9 日,以上代码在 Java 8 上编译。
那么,Java 8 可以做蛋糕一样的模式吗?是的。
它是像 Scala 一样简洁,还是像 Java 中的其他模式一样有效(即依赖注入)?可能不是,上面的草图需要大量文件,而且不如 Scala 简洁。
总之:
val
并且var
可以通过使用静态哈希图(和延迟初始化)来模拟,或者由类的客户端简单地将值存储在他们身边(就像 UserService 一样)。this.getClass()
默认接口方法来发现我们的类型。也许你可以在 Java 8 中做这样的事情
interface DataSource
{
String lookup(long id);
}
interface RealDataSource extends DataSource
{
default String lookup(long id){ return "real#"+id; }
}
interface TestDataSource extends DataSource
{
default String lookup(long id){ return "test#"+id; }
}
abstract class App implements DataSource
{
void run(){ print( "data is " + lookup(42) ); }
}
class RealApp extends App implements RealDataSource {}
new RealApp().run(); // prints "data is real#42"
class TestApp extends App implements TestDataSource {}
new TestApp().run(); // prints "data is test#42"
但这绝不比普通/旧方法更好
interface DataSource
{
String lookup(long id);
}
class RealDataSource implements DataSource
{
String lookup(long id){ return "real#"+id; }
}
class TestDataSource implements DataSource
{
String lookup(long id){ return "test#"+id; }
}
class App
{
final DataSource ds;
App(DataSource ds){ this.ds=ds; }
void run(){ print( "data is " + ds.lookup(42) ); }
}
new App(new RealDataSource()).run(); // prints "data is real#42"
new App(new TestDataSource()).run(); // prints "data is test#42"
我最近对此做了一个小的概念验证。您可以在此处查看博客文章:http: //thoredge.blogspot.no/2013/01/cake-pattern-in-jdk8-evolve-beyond.html和 github 存储库:https ://github.com/thoraage /cake-db-jdk8
基本上你可以做到,但你至少面临两个障碍,使其不如 Scala 流畅。首先,Scala 特征可以有状态,而 Java 的接口不能。许多模块需要状态。这可以通过创建一个通用状态组件来保存此信息来解决,但这需要在一个类中。至少部分。第二个问题是接口中的嵌套类更类似于类中的静态嵌套类。所以你不能直接从模块类访问接口方法。默认接口方法可以访问这个范围,并且可以将它添加到模块类的构造函数中。
一些实验表明没有:
嵌套类自动是静态的。这本质上不像蛋糕:
interface Car {
class Engine { }
}
// ...
Car car = new Car() { };
Car.Engine e = car.new Engine();
error: qualified new of static class
Car.Engine e = car.new Engine();
因此,显然,是嵌套接口,尽管更难哄出错误消息:
interface Car {
interface Engine { }
}
// ...
Car car = new Car() { };
class Yo implements car.Engine {
}
error: package car does not exist
class Yo implements car.Engine {
// ...
class Yo implements Car.Engine {
}
// compiles ok.
因此,没有实例成员类,您就没有路径依赖类型,这对于蛋糕模式来说基本上是必需的。所以至少,不,不是直接的方式,这是不可能的。
忽略 Java 8 中的新功能,理论上您可以使用编译时AspectJ ITDs在 Java 5 及更高版本中执行 Cake Pattern 。
AspectJ DTO 允许您制作 Mixins。唯一烦人的事情是您必须制作两个工件:方面 (ITD) 和接口。但是,ITD 允许您做一些疯狂的事情,例如向实现接口的类添加注释。