Мне просто интересно: с 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 {}
Вышеприведенное компилируется на Java 8 по состоянию на 9 января 2013 года.
Итак, может ли Java 8 создать шаблон как торт? Да
Является ли он таким же кратким, как Scala, или таким же эффективным, как другие шаблоны в Java (например, внедрение зависимостей)? Вероятно, нет, приведенный выше скетч требует большого количества файлов и не такой лаконичный, как Scala.
В итоге:
val
и var
можно эмулировать с помощью статической хэш-карты (и ленивой инициализации) или с помощью клиента класса, просто сохраняющего значение на своей стороне (как это делает UserService).this.getClass()
в методе интерфейса по умолчанию.this
и this.getClass()
в теле метода по умолчанию, и вы можете добавить дополнительное состояние через карту слабой идентификации. Однако в примере с ведением журнала это просто не способ Java; нет ничего плохого в простом/старом решении добавления поля экземпляра final Logger logger=Logger.of(this);
для достижения эффекта миксина.
- person irreputable; 10.01.2013
Может быть, вы можете сделать что-то подобное в 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 — нет. Многие модули нуждаются в состоянии. Это можно исправить, создав компонент общего состояния для хранения этой информации, но это должно быть в классе. По крайней мере частично. Вторая проблема заключается в том, что вложенный класс в интерфейсе больше похож на статический вложенный класс в классе. Таким образом, вы не можете получить доступ к методам интерфейсов непосредственно из класса модуля. Метод интерфейса по умолчанию имеет доступ к этой области и может добавить ее в конструктор класса модуля.
Несколько экспериментов показывают, что нет:
Вложенные классы автоматически статичны. Это по своей сути uncakelike:
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, вы теоретически можете использовать шаблон Cake в Java 5 и выше, используя время компиляции ITD AspectJ.
DTO AspectJ позволяют создавать миксины. Напрягает только то, что придется делать два артефакта: аспект (ИТД) и интерфейс. Однако ITD позволяют вам делать некоторые сумасшедшие вещи, такие как добавление аннотаций к классам, реализующим интерфейс.