Java8的蛋糕模式可能吗?

时间:2013-01-10 00:12:55

标签: java scala java-8 cake-pattern

我只是想知道:使用Java 8,并且可以在接口中添加实现(有点像Scala特性),是否可以像在Scala中一样实现cake pattern

如果是,有人可以提供代码段吗?

5 个答案:

答案 0 :(得分:25)

在其他答案的启发下,我提出了以下(粗略)类层次结构,类似于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那样简洁。

总结:

  • 可以通过扩展我们期望的基本接口来模拟自我类型(根据蛋糕模式的需要)。
  • 接口不能有内部类(如@Owen所述),所以我们可以使用匿名类。
  • valvar可以通过使用静态hashmap(和延迟初始化)来模拟,或者由类的客户端简单地将值存储在它们一边(就像UserService那样)。
  • 我们可以在默认界面方法中使用this.getClass()来发现我们的类型。
  • 正如@Owen所说,使用接口是不可能的路径依赖类型,因此完整的蛋糕模式本身是不可能的。但是,上面显示可以使用它进行依赖注入。

答案 1 :(得分:3)

我最近对此做了一个小概念验证。你可以在这里看到博客帖子:http://thoredge.blogspot.no/2013/01/cake-pattern-in-jdk8-evolve-beyond.html和github repo:https://github.com/thoraage/cake-db-jdk8

基本上你可以做到这一点,但是你面对至少两个障碍,使它比Scala更不光滑。首先,Scala特性可以具有状态,而Java的接口则不能。许多模块都需要状态。这可以通过创建一个通用的状态组件来保存这些信息来解决,但这需要在一个类中。至少部分地。第二个问题是接口中的嵌套类更类似于类中的静态嵌套类。因此,您无法直接从模块类访问interfaces方法。默认接口方法可以访问此作用域,并可以将其添加到模块类的构造函数中。

答案 2 :(得分:2)

一些实验表明没有:

  • 嵌套类是自动静态的。这本质上是不相似的:

    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.
    

因此,如果没有实例成员类,则没有路径依赖类型,即 基本上必要的蛋糕模式。所以至少,不,不是以直截了当的方式, 这是不可能的。

答案 3 :(得分:2)

也许你可以在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"

答案 4 :(得分:1)

忽略Java 8中的新功能,理论上可以使用编译时AspectJ ITDs在Java 5及更高版本中执行Cake Pattern。

AspectJ DTO's allow you to make Mixins。唯一令人烦恼的是你必须制作两个工件:方面(ITD)和界面。但是ITD允许你做一些疯狂的事情,比如在实现接口的类中添加注释。