2015-10-12 15 views
6

Od pewnego czasu zacząłem uczyć się scala i teraz patrzę na wzór ciasta. Mam przykład z hereZnaczenie wzoru ciasta w scala

trait UserRepositoryComponent { 
    def userLocator: UserLocator 

    trait UserLocator { 
    def findAll: List[User] 
    } 
} 

trait UserRepositoryJPAComponent extends UserRepositoryComponent { 
    val em: EntityManager 

    def userLocator = new UserLocatorJPA(em) 

    class UserLocatorJPA(val em: EntityManager) extends UserLocator { 
    def findAll = { 
     println("Executing a JPA query") 
     List(new User, new User) 
    } 
    } 
} 

trait UserServiceComponent { 
    def userService: UserService 

    trait UserService { 
    def findAll: List[User] 
    } 
} 

trait DefaultUserServiceComponent extends UserServiceComponent { 
    this: UserRepositoryComponent => 

    def userService = new DefaultUserService 

    class DefaultUserService extends UserService { 
    def findAll = userLocator.findAll 
    } 
} 

Dla mnie to wygląda zbyt wielu standardowy kod do uzyskania repozytorium WZP wtryskiwanego do służby.

Jednak ten kod będzie zrobić to samo z dużo mniejszą liczbą linii

trait UserRepository { 
    def findAll 
} 

trait JPAUserRepository extends UserRepository { 
    val em: EntityManager 
    def findAll = { 
    em.createQuery 
    println("find using JPA") 
    } 
} 

trait MyService { 
    def findAll 
} 

trait MyDefaultService extends MyService { 
    this: UserRepository=> 
} 

uruchamianiu obu scenariuszy.

val t1 = new DefaultUserServiceComponent with UserRepositoryJPAComponent { 
    val em = new EntityManager() 
} 
t1.userService.findAll 


val t2 = new MyDefaultService with JPAUserRepository { 
    val em = new EntityManager 
} 

t2.findAll 

Drugi scenariusz używa znacznie mniej kodu i używa DI. Czy możesz mi pomóc zrozumieć, jakie dodatkowe korzyści przynosi wzór ciasta.

+0

Jak mówi @Archeg, drugi przykład jest również wariant ciasto wzorca. –

Odpowiedz

2

Jak rozumiem, nie ma zbyt dużej różnicy. W rzeczywistości wzór ciasta to IoC. Jest to po prostu idea implementacji IoC i DI, bez oddzielnej struktury DI, ale tylko z kodem scala. Prawdopodobnie powinieneś preferować go w oddzielnym kontenerze DI, chyba że potrzebujesz więcej funkcji.

Wygląda na to, że oba przykłady to wzory ciast. Przynajmniej tak to rozumiem. Ale Martin nie nazwał tego "wzorem tortu" w swojej książce i opieram moją wiedzę o scala mosly na jednej książce, więc być może czegoś mi brakuje. W moim rozumieniu jest to, że ciasto wzór jest idea łączenia różnych cech, aby osiągnąć DI

myślę Martin wymienione szczegółowo w swojej książce, że jest w porządku, aby korzystać DI -containers takich jak wiosną w Scala, ale niestety nie mogę znaleźć to miejsce

Aktualizacja

Znaleziono go: http://www.artima.com/pins1ed/modular-programming-using-objects.html Zobacz ostatni akapit 27.1 The problem. Ale jak powiedziałem, on nie mówi o „ciasta” tutaj, chociaż idea wygląda tak samo z artykułu dałeś

Update 2

Właśnie ponownie przeczytać moją odpowiedź i zrozumiałym, że muszę aby go poprawić, ponieważ nie w pełni odpowiada na pytanie.

Powinieneś preferować "wzór ciasta", ponieważ jest prostszy.Jeśli używasz Springa, musisz zachować konfigurację, niezależnie od tego, czy jest to XML czy adnotacje, możesz również mieć pewne wymagania dotyczące swoich zajęć (nie używałem Springa, więc nie jestem pewien, czy są jakieś), i masz by przynieść ze sobą całą Wiosnę. Z wzorem tortowym wystarczy napisać kod tak prosty, jak jest (twój drugi przykład jest prosty, powinieneś się zgodzić). To, co jest miłe w scala, to to, że możesz zrobić z nim wiele rzeczy i używać tylko kilku frameworków - jeśli porównasz to z Javą - zwykle używasz znacznie więcej zewnętrznych bibliotek. Jeśli potrzebujesz bardziej zaawansowanej funkcjonalności, jak proxy - możesz przełączyć się na Spring lub kontynuować używanie Scala i rozwiązać problemy z samym językiem, miejmy nadzieję, scala jest niezwykle potężna i powinna obejmować nawet skomplikowane przypadki.

Różnica między dwoma podanymi fragmentami kodu jest po prostu abstrakcją: pierwsza z nich ma jeszcze jedną abstrakcję ponad operacjami zdefiniowanymi w repozytorium i usłudze i nie są one częścią wzorca. Nie czuję, żeby to było wymagane, ale autor postanowił pokazać to w ten sposób.

2

To, co daje wzór tortu w porównaniu z układem wtryskowym typu IoC, polega na tym, że w czasie kompilacji masz wyraźną zależność od implementacji, której będziesz używał, w przeciwieństwie do konfiguracji, która obejmuje kontrole w czasie plików XML lub adnotacji. Oznacza to, że rozróżnienie to czas kompilacji w stosunku do czasu wykonania.

Podczas testowania można wprowadzać fałszywe implanty i po prostu je miksować. W produkcji można używać "prawdziwych" implów i po prostu je mieszać. Kompilator powie, kiedy coś złego zrobiono.

(Rzeczywistość jest dużo bardziej skomplikowana, jak można dostać zerowe problemy wskaźnik i różnego rodzaju braku determinizmu czy mieszanie i dopasowywanie obiektów statycznych).

+0

IoC nie jest w żaden sposób związany z XML. Zwykle można ustawić zależności w kodzie w czasie kompilacji, a ja osobiście wolę to w ten sposób. To wciąż IoC – Archeg

+0

@Archeg Moja odpowiedź jest barwiona przez moje doświadczenia ze Spring i innymi podobnymi rozwiązaniami IoC, które zawierają duże ilości plików konfiguracyjnych XML. – wheaties

+0

Czy druga metoda nie pozwala również na mieszanie obu próbnych/rzeczywistych implementacji. Complier zgłosi błędy, jeśli spróbujesz miksować w niewłaściwych typach. Nadal nie widzisz przewagi Cake przynosi cały ten dodatkowy kod. –

1

W drugim przykładzie wystarczy użyć implementacji JPAUserRepository z findAll. Ale, w zasadzie, problem z drugim podejściu moim zdaniem jest to, że za pomocą interfejsu API narazić biznesowych, które nie powinny być narażone (aka UserRepositor api should't być narażeni podczas korzystania z obiektu typu t2Service)

Rzeczywiście ciasto wzór wprowadza nieco więcej kodu, niż można napisać za pomocą jakiegoś framework IoC. Ale możesz również uporządkować swój kod w nieco inny sposób. Na przykład wpisanie cechy komponentu nie dla niektórych usług, ale dla każdej grupy usług logicznie powiązanych. Jako przykład, wszystkie rodzaje usług repozytorium mogą znajdować się pod numerem RespositoryComponent, a wszystkie rodzaje usług biznesowych mogą znajdować się w BusinessLogicComponent). Aby porównać to z wiosną, idea polega na tym, że cechą implementacji składnika jest właśnie ta sama deklinacja XML fasoli.

Aby korzystać sprężynę jak DI w Scala Proponuję spojrzeć na MacWire

+0

Dzięki, zgadzam się. Wierzę, że moduły są kluczem. To nie tylko DI. Ciasto pozwala tworzyć moduły i moduły mogą dziedziczyć się nawzajem. Adnotacje typu self umożliwiają powiązanie modułów. Czytam moduły i jest o tym bardzo interesująca dyskusja. –