使用Java8的蛋糕模式可能吗?

2022-09-01 12:02:58

我只是想知道:有了Java 8,以及在接口中添加实现的可能性(有点像Scala特征),是否有可能实现蛋糕模式,就像我们在Scala中所做的那样?

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


答案 1

从其他答案中汲取灵感,我想出了以下(粗略的)类层次结构,类似于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所述),因此我们可以使用匿名类。
  • val并且可以通过使用静态哈希映射(和延迟初始化)来模拟,或者由类的客户端简单地将值存储在其一侧(如UserService所做的那样)。var
  • 我们可以通过在默认接口方法中使用来发现我们的类型。this.getClass()
  • 正如@Owen所指出的,使用接口不可能实现路径依赖类型,因此完整的蛋糕模式本质上是不可能的。但是,上面显示,可以使用它进行依赖注入。

答案 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"

推荐