Eftersom jag har fått lite frågor kring det här med IoC eller Dependency Injection som det också kallas så tänkte jag ta en liten lätt beskrivning kring det här. Exemplen jag har med är skrivna i Java men jag tror att de flesta som programmerar klarar av att läsa dessa. Som IoC ramverk i exemplet använder jag Pico (www.picocontainer.org). Denna finns i skarp version (open source) för Java och i en .NET version (open source) som jag inte själv har testat. Mycket bra inlägg. Typ denna.. jag kanske missat själva poängen men det går väl göra samma sak utan något 3e parts framework? Roggan, fast samma sak går ju tydligen i java Roggan, Jag är inne på Roggans linje - detta är väl ungefär lika nytt som hjulet? Både .NET (Activator.CreateInstance) och Java (Class.forName) löser detta utan något 3e parts ramverk. Vet inte om det va min tråd som startade allt detta!? Nee, kunde bara inte se riktig vad det Nils beskrev skulle vara "bra" till. Kan vara jag som missat vad Nils försökte förmedla och då vill jag gärna att han förtydligar. Framför allt så har jag svårt att de vad Container objektet spelar för roll i det hela. Container objeketet används för att registrera de klasser som sedan ska kunna användas genom att ange en "key", med hjälp av denna key så hämtas rätt typ av klass från container objektet för användning, kan tex vara olika klasser som går mot olika data källor. Vilken klass som ska användas sker i runtime och inte vid kompilering. Hej! Ok, ni har haft lite frågor kring det här ser jag. Först och främst, jag skrev det här inlägget eftersom jag fått frågor både i forumet och via iMail vad det här "Dependency Injection" är för något och jag tänkte jag kunde presentera det. Det är kul att det kommit lite kommentarer och frågor och jag ska göra mitt bästa för att besvara dem. Kanske var mitt exempel för enkelt men jag försöker utvidga det lite nedan. Någon skrev att "detta är väl ungefär lika nytt som hjulet" men jag håller absolut inte med...kolla på exemplet nedan så tror jag ni förstår bättre. Nils: oke jag röstar för an artikel och exempel som bättre beskrivet vitsen med det hela , dom exempel du dragit nu går ju fortfarande att lösa utan pico utan problem Roggan: fast nu har du nog inte läst något av mina inlägg. >fast nu har du nog inte läst något av mina inlägg. jag tror jag är med på när DI är bra att använda .. dock tror jag dina exempel var lite för små för att DI ska vara bättre än något annat.. Jahapp, några tycks förstå konceptet och några tycks behöva tänka lite längre tid för att förstå det. Huvudsaken är dock ATT ni förstår konceptet i sig och kanske kan det passa er alldeles utmärkt att använda någon gång. det jag och Andreas undrade över var vad kontainern fyllde för funktion och med dina exempel så framgick det inte hur och varför det var bra att använda pico. för att visa för nisse hur det GÅR att lösa det hela med de exempel jag gett så kommer det lite kod här. Att det alltid ska bli så inflamerat här. Men nåja...ett sista inlägg i den här tråden...och det blir återigen Roggans frågor jag besvarar. ok jag ber om ursäkt för eventuella bitchslaps men blev lite irriterad när du postade något som "min" kod när jag aldrig varit i närheten av att förespråka den koden du postade.. <rogan> nu får du väl ge dig.. Så jag skulle skrivit en storskalig applikation? Nu skojar du igen...du måste väl själv kunna sätta ett exempel i ett större scenario. Annars hade jag ju fått skriva en bok! jag tror fan du är autistisk , du gav ett exempel , jag gav en lösning på problemet , vem som hellst kan ta koden i mina exempel och kompilera och köra och se att dom fungerar fint för det scenario med taxservice som du gav. hur gärna du än vill att den inte ska fungera så fungerar nisseklasserna och gör precis det dom ska... <b>du är nog den drygaste jävla stålle jag stött på här , jag tycker du ska ransaka dig själv och fundera över varför du lyckats göra dig obekväm med varenda person du haft kontakt med på den här sajten på bara några få veckor.</b> Sky, Kära Sky... "er som är så jävla insnöad på .NET och sitter och sli**** varandra i r***** på denna site." Oj, oj, ov vilka proportioner det här tar...det en påhoppet värre än det andra. Jag skrev att det senaste inlägget jag gjorde var mitt sista i denna tråd men jag är bara tvungen att kommentera all den här uppståndelsen. Phu... Pga alla påhopp o skit här :-( Så tänkte jag be Pelle ta bort denna tråden (om han kan) hoppas det är ok för er alla? Dependency Injection/Inversion of Control
Dependency Injection kallas också ibland skämtsamt "The Hollywood Principle", dvs "Don't call me, I call you" och det är precis vad det handlar om.
Vi börjar med ett exempel som vi utgår ifrån:
<code>
public class MyTaxService implements TaxInterface {
private TaxDAO dao;
public MyTaxService() {
TaxDAO = new TxtTaxDAO();
}
public double calculateTax(double income, String municipal) {
double tax = dao.findTax(municipal);
return income * tax;
}
}
</code>
Inga konstigheter här. Vi har en service klass, MyTaxService, som räknar ut skatten åt oss genom metoden calculateTax(). Denna metod använder ett DAO (Data Access Object) för att hämta skattesatsen som ska användas beroende på i vilken kommun man bor. DAO objektet är helt enkelt ett objekt vars enda uppgift är att hämta data. Jag vill dock att man ska kunna hämta skattesatsen på flera olika sätt: Via en textfil, via en webservice, via databas, kanske via flera olika typer av datbaser (Oracle, SQL Server etc), jag vill ge mina kunder valmöjligheter och jag vet inte säkert i förväg hur de har åtkomst till skattesatser.
Jag skapar interfacet TaxDAO
<code>
public interface TaxDAO {
double findTax(String municipal);
}
</code>
Detta interface använder jag i min MyTaxService klass som ni ser. Jag har nu fått en trevlig löskopplad implementation. I konstruktorn i MyTaxService ser ni att jag skapar en ny instans av klassen TxtTaxDAO. Detta är en klass som implementerar TaxDAO och som använder en .txt fil som datakälla för att hämta rätt skattesats. Det här funkar kanon för min första kund som använder just .txt filer. Min andra kund är dock inte lika glad. De använder WebServices direkt mot skatteverket för att hämta rätt skattesats. Vad ska jag nu göra? Jag vill allstå använda olika versioner av TaxDAO beroende på vilken kund jag leverar till, men jag vill inte tvingas leverera olika kompilerade versioner till varje kund. Jag skriver klassen WebServiceTaxDAO som också implementerar TaxDAO...men sedan? Det är här Dependeny Injection kan komma in och hjälpa mig. Dependency Injection löskopplar systemet ännu mer och ger mig möjligheter att göra ganska fräcka saker.
Så, att direkt instantiera mitt objekt i konstruktorn var ingen bra lösning eftersom jag inte kan plugga in andra komponenter som gör samma sak men som använder en annan datakälla. Syftet med Dependency Injection är egentligen att populera objekten eller services åt oss. Man använder ett objekt som en typ av assembler (MutablePicoContainer nedan) som skapar vårt MyTaxService objekt. Vi börjar med att ändra konstruktorn i MyTaxService till att se ut så här:
<code>
public MyTaxService(TaxDAO dao) {
this.dao = dao;
}
</code>
Vi tog bort instansieringen av objektet i konstruktorn och ordnade så att konstruktorn tar interfacet TaxDAO som argument istället. Vi överlåter nu till Containern (t ex Pico eller Spring framework) att skapa MyTaxService objektet åt oss och att instansiera det med TaxDAO. Det är detta överlåtande, don't call me I call you, som just är Dependency Injection.
Vi fortsätter med exemplet. Jag skapar en konfig klass som använder Pico där jag måste tala om vilken klass som ska associeras med vilket interface. Det går också alldeles utmärkt att bara registrera konkreta klasser.
<code>
private MutablePicoContainer config() {
MutablePicoContainer container = new MutablePicoContainer();
container.registerComponentImplementation(TaxDAO.class, TxtTaxDAO.class);
container.registerComponentImplementation(TaxService.class, MyTaxService.class);
return container;
}
</code>
Bättre än ovanstående exempel är att använda en xml-fil för att konfigurera just detta, alltså registreringen av klasser och interface, så räcker det alltså att speca klasser och interface i en xml-fil per kund.
Genom att sedan hämta ut containern och efterfråga ett objekt, MyTaxService, så kommer Pico att fixa instansieringen av vårt DAO objekt och väljer det som är konfigurerat för just den här kunden. Om det är en WebService, textfil eller annat vet applikationen inte om och behöver inte bry sig om heller.
<code>
public void test() {
MutablePicoContainer container = config();
TaxService taxService = (TaxService)container.getComponentInterface(TaxService.class);
long tax = taxService.findTax(1000000, "danderyd");
System.out.println("Your tax is: " + tax);
}
</code>
Och det är allt. Det här var bara ett enkelt test och exempel. Observera att man inte någonstans behöver skicka med någon instans av TaxDAO till TaxService. Det är just detta som Pico sköter...och det är just detta som är Dependency Injection. Det är inte i alla lägen som Dependency Injection passar att använda men det kan vara en kul input som kan trigga igång tankar och idéer. Det finns också olika typer av Dependency Injection, Constructor based (som i detta exempel), setter based och andra "lokala" varianter...men konceptet är ändå detsamma...låt containern plocka ihop dina objekt/services.
Hoppas att exemplet var ok. Annars får ni gärna höra av er med frågor och kommentarer. Vill ni läsa mer så sök efter dependency injection eller inversion of control på google så hittar ni massor.
/NilsSv: Dependency Injection/Inversion of Control
Vill nämna att nästa version av ASP.Net använder "settings injection" som för deras "plugable solution (Plugin)", med skl "providers". En provider ärver en abstrakt klass eller ett interface. Med hjälp av web.config, kan dessa provider konfigureras. Några features i kommande ASP.net som är provider baserade, är: Profile, MemberShip, Roles, Session, Perosonalization, Localization med mfl. Större delen av nya ASP.net bygger på providers som går att bytas ut enkelt med hjälp av web.config eller i runtime.
Även i .Net 1.x finns det några exempel på lösningar som använder sig av Dependency Injection, vi har tex PAG's applikationsblock.
/Fredrik Normén NSQUARED2
http://fredrik.nsquared2.netSv: Dependency Injection/Inversion of Control
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspnet/html/asp04212004.asp
Mvh JohanSv: Dependency Injection/Inversion of Control
c#public class MyTaxService : TaxInterface
{
private ITaxDAO dao= null;
public MyTaxService()
{
dao = (ITaxDAO)Activator.CreateInstance (mysettings.assembly,mysettings.class);
}
public double calculateTax(double income, String municipal)
{
double tax = dao.findTax(municipal);
return income * tax;
}
}
här gör jag ju precis samma sak utan att blanda in någon annan kod och det blev inte mer kod heller
användaren av klassen behöver bara instansiera mytaxservice som vanligt och allt är frid och fröjd
eller?
//Roger
Sv: Dependency Injection/Inversion of Control
Ja det går.
.Net har en hel del saker implicit som Java idag inte har. Sedan om det är en fördel eller nackdel är en annan sak, fördelen är väl att du har allt på ett ställe medans nackdelen är att du blir mer låst at bara kunna MS saker och inte få koll på 3de parters lika lätt.
Mvh JohanSv: Dependency Injection/Inversion of Control
ITaxDAO dao=Class.forName(mysettings.ClassName).newInstance());
så varför skulle jag vilja ha koll på just den här 3epartslösningen om jag kan lösa samma sak på ett lättare och snyggare sätt utan den?
(eller finns det några mer komplexa lösningar med IoC som inte går på samma sätt?)
//RogerSv: Dependency Injection/Inversion of Control
Jag hade för mig Class.forName var en 3de parts sak, kanske uppfattat det fel då jag läste om den. Var ett tagsedan dock, eller så har jag bara rört i hop det. (troligen det sista)
Jag är oxå nyfiken vad 3de part saken gör. Min teori är väl att det då fungerar mer som Provider Pattern. Att den returnerar dig ett objekt som du specar i någon configuration eller liknande.
Mvh JohanSv: Dependency Injection/Inversion of Control
Jag måste missa något vitalt här? Och vad medför containern för nytta?Sv: Dependency Injection/Inversion of Control
Det jag ville hag sagt med mitt inlägg, var lösningar som idag använder sig av Dependency Injection.
/Fredrik Normén NSQUARED2
http://fredrik.nsquared2.comSv: Dependency Injection/Inversion of Control
Sv: Dependency Injection/Inversion of Control
/Fredrik Normén NSQUARED2
http://fredrik.nsquared2.comSv: Dependency Injection/Inversion of Control
Här hittar ni en intressant artikel om det hela från Martin Fowler:
http://martinfowler.com/articles/injection.html
Vidare skriver Rod Johnson om det hela i sin bok "J2EE Development without EJB".
Mvh
Jimmy
www.jnsk.se/weblog/
###Sv: Dependency Injection/Inversion of Control
Till att börja med...de förslag som ni har skrivit fungerar...inga bekymmer, fast de behöver ganska mycket jobb till för att de ska matcha en container som t ex Pico, och det finns en fundamental skillnad. Ni skapar själva klassen, en enkel typ av lookup, vilket man inte gör med Dependency Injection (DI). Istället för att göra en "lookup" så deklarerar men dessa dependencies eller beroenden och det är containern som sätter ihop dem åt oss. Thats it...inget mer magiskt än så...det är bara "the other way around" så att säga. Det är alltså inte komponenten i sig som skapar sina objekt som den beror på utan det är något som sköts "utifrån". Det är fel att säga att det ena är mer rätt än fel men jag kan ge er lite andra exempel på när det kan vara trevligt att använda sig av Dependency Injection.
Vi skriver om konstruktorn till MyTaxService klassen:
<code>
public MyTaxService(TaxDAO taxDAO) {
this.dao = taxDAO;
}
</code>
Detta är en bättre design av klassen, att ta TaxDAO som argument i konstruktorn, eftersom den då blir mer öppen och inte knuten till att använda DI eller Class.forName internt i konstruktorn.
Nu blir det genast lite värre med de förslagen ni gav. Ni tvingas göra något åt detta hållet...TaxDAO objektet går bra att skapa med .newInstance()...men hur ska ni sedan skapa MyTaxService? Knappast med .newInstance() eftersom det då skapar ett nytt defaultobjekt med tom konstruktor. Ska ni lösa detta i Java eller C# så får ni skriva någon grunka med reflection (typ (Class.forName(mysettings.ClassName)).constructors(), loopa igenom och hitta rätt konstruktor och anropa den med constructor.newInstance(Object[] params) och casta och ha er)...vilket i och för sig kan vara kul men bättre då att använda en produkt som redan fixar det åt dig :) Med t ex Pico gör man:
<code>
// görs en gång vid initalisering av en applikation t ex
MutablePicoContainer pico = new DefaultPicoContainer();
pico.registerComponentImplementation(TaxService.class, MyTaxService.class);
pico.registerComponentImplementation(TaxDAO.class, TxtTaxDAO);
// och använder det sedan överallt med
TaxService service = (TaxService)pico.getComponentInstance(TaxService.class);
</code>
En enkel rad...det är nice :)
Och vill man krångla till exemplet ytterligare kan man lägga till att även TxtTaxDAO vill ha en inparameter till sin konstruktor, t ex en sökväg till en fil i filsystemet. Detta löser man i Pico på följande sätt (fast kanske inte med ful hårdkodning men jag tror ni förstår principen)
<code>
Parameter[] initParams = {new ConstantParameter("taxes.txt")};
pico.registerComponentImplementation(TaxDAO.class, TxtTaxDAO, initParams);
</code>
DI via konstruktorer är bara en typ som man kan använda. Man kan även använda setter-based DI vilket betyder att vid skapandet av klassen så injectas parametrar, Objekt eller primitiver i en class setter metod(er). Att använda konstruktor baserad DI eller setter baserad DI beror helt på klassen man implementerar, dess syfte och design...orkar inte skriva om det ikväll.
Nya frågor eller funderingar?
/NilsSv: Dependency Injection/Inversion of Control
Ett tips, om du har tid så tycker jag att du ska skriva en artikel om detta och publicera den på Pellesoft. Fler kommer då att kunna ta del av informationen (Alla vet inte om denna tråden).
/Fredrik Normén NSQUARED2
http://fredrik.nsquared2.comSv: Dependency Injection/Inversion of Control
// görs en gång vid initalisering av en applikation t ex
MutablePicoContainer pico = new DefaultPicoContainer();
pico.registerComponentImplementation(TaxService.class, MyTaxService.class);
pico.registerComponentImplementation(TaxDAO.class, TxtTaxDAO);
// och använder det sedan överallt med
TaxService service = (TaxService)pico.getComponentInstance(TaxService.class);
eftersom du trots allt har hårdkodat "nyckeln" getComponentInstance(<b>TaxService.class</b>);
så kan du ju lika gärna ersätta det med ett hårdkodat anrop.
så går det ju göra med:
public static TaxService GetTaxService()
{
//bygg objektet här
return new MyTaxService(params...); //eller använd activator-forName om det ska vara dynamiskt
}
//så anropar man det med:
TaxService service = MyTools.GetTaxService(); //<- en rad , utan casting , lättläst ... nice ;)
//Roger
Sv: Dependency Injection/Inversion of Control
Det handlar om att först vid runtime så vet applikationen vilken klass den ska använda.
Till Pico så finns en wrapper som går mot XML, där du definierar klasser. Så genom den XML filen kan du när du vill ändra så en klass byts ut mot en annan med samma interface, utan att behöva kompilera om applikationen.
Du kanske har en klass som går mot en MS Sql databas, men en annan kund vill gå mot MySql eller kanske Oracle etc. För att då slippa kompilera om hela din applikation och ändra överallt där du använder dig av klassen som går mot MS Sql, så ändrar du bara i en fil.
/Fredrik Normén NSQUARED2
http://fredrik.nsquared2.comSv: Dependency Injection/Inversion of Control
det var ju precis det jag beskrev i min första post , att det går att göra det med activator.createinstance eller class.forName i java.
jag kan ju lätt lägga mina inställningar i app.config och fån dessa keys skapa rätt klass med activator.createinstance
det handlar ju om 1 rad kod för att lösa detta.
det jag undrar över är vad jag har för nytta av det stora feta extra paketat med kod som man får med pico.
vad för magiska saker förutom "activator.createinstance(mysettings.assemblyname,mysettings.classname);" gör den?
som jag resonerar utifrån de exempel vi fått här:
eftersom "nyckeln" som används för att plocka ut den dynamiskt byggda klassen ut pico containern är hårdkodad så kan jag ju ersätta den raden med ett typat metodanrop , så jag slipper castning och det blir lättläst.
i den metod som jag nu anropar istället kan jag ju byggaihop mitt objekt hur jag vill ,
tex:
* hårdkoda.
* dynamiskt via .net activator.createinstance, java class.forName(..), vb/script createobject
* dynamiskt via script , lagra en hel scriptsnutt i en config fil och låt scriptet returnera ett objekt av rätt subklass/implementation (eg jscript.net , vbscript , javascript eller rent av kompilera en factoryklass on the fly i valfrittspråk)
allt detta går att göra med minimalt med kod utan stora 3eparts libbs.
och jag kan inte se vad som skulle göra det här mindre dynamiskt än pico?
//RogerSv: Dependency Injection/Inversion of Control
Kan nog stämma, jag mer eller mindre skummade igenom texten, hoppas du inte tog illa upp?
Istället för att själv behöva hämta klasser från en container eller en fil, samt sköta initieringen och injection, så sköter ramverket det åt dig. Så du kan återanvända det om och om igen. Jag är inte 100% insatt i PicoContainer.
http://www.picocontainer.org/One+minute+description
/Fredrik Normén NSQUARED2
http://fredrik.nsquared2.comSv: Dependency Injection/Inversion of Control
men , här är iaf hur jag fattat det..
anta att vi har följande interfaces:
IHus
ITak
ITegelTakMaterial
IGlasTakMaterial
IVägg
ITegelVäggMaterial
ITräVäggMaterial
sedan har vi ett gäng implementationer
Hus : IHus
BrutetTak : ITak
PlastTak : ITak
GlasTak : ITak
TakTegel1 : ITegelTakMaterial
TakTegel2 : ITegelTakMaterial
TakHalm : ITegelTakMaterial
VittTakGlas : IGlasTakMaterial
RöttTakGlas : IGlasTakMaterial
TegelVägg : IVägg
TräVägg : IVägg
PlastVägg : IVägg
RöttTegel : ITegelVäggMaterial
VittTegel : ITegelVäggMaterial
BjörkPlankor : ITräVäggMaterial
GranPlankor : ITräVäggMaterial
så.. nu har vi en väldig massa olika material och delar som kan sättas ihop på olika sätt
"Hus" har dependencies till "IVägg" och "ITak" men skiter för övrigt i vad dessa består av.
"BrutetTak" har en dependency till ITegelTakMaterial
medans "PlastTak" inte har en dependency till något alls
"TegelVägg" har en dependency till ITegeöVäggMaterial
och "TräVägg" har en dependency till ITräVäggMaterial
och PlastVägg har inga dependencies
nu kan jag alltså configga en container att innehålla:
(i pseudo kod)
mypic.register( IHus , Hus )
mypic.register( IVägg , TräVägg)
mypic.register( ITräVäggMaterial , BjörkPlankor )
mypic.register( ITag , BrutetTak )
mypic.register( ITegelTakMaterial , TakHalm )
IHus hus=mypic.getInstance( IHus )
eftersom kontainern känner till alla dependencies (via konstruktorerna) så kan kontainern nu lätt montera en instans med de delar vi specat ovan .. utan att någon av delarna i sig specat vad dom ska bestå av.
eller så kan vi montera huset som:
mypic.register( IHus , Hus )
mypic.register( IVägg , PlastVägg )
mypic.register( ITag , PlastTak)
IHus hus=mypic.getInstance( IHus )
där vi inte enns har samma mängd objekt som behöver skapas eftersom plastväggar och plasttak inte har dependencies till något annat.
lägger vi då dessa configs i tex xml så kan man förmodligen bygga väldigt komplexa hirarkier.
men i Nils fall med en service klass och olika varianter av dao klasser så får jag nog säga att det känns väldigt overkill.
//Roger
Sv: Dependency Injection/Inversion of Control
Mest kommenterar kring det här har jag fått från "Roggan" så jag försöker svara på dina kommenterar här.
<roggan>
oke jag röstar för an artikel och exempel som bättre beskrivet vitsen med det hela"
</roggan>
Sorry, det blir ingen artikel...duger bra i detta forum tycker jag. Tycker också att exemplen talar för sig själva. Men behövs det mer exempel så hör av er.
<roggan>
dom exempel du dragit nu går ju fortfarande att lösa utan pico utan problem
</roggan>
Det gör de, men vi kommer till detta längre fram.
<roggan>
eftersom du trots allt har hårdkodat "nyckeln" getComponentInstance(TaxService.class);
så kan du ju lika gärna ersätta det med ett hårdkodat anrop.
så går det ju göra med:
public static TaxService GetTaxService()
{...}
{
//bygg objektet här
return new MyTaxService(params...); //eller använd activator-forName om det ska vara dynamiskt
}
//så anropar man det med:
TaxService service = MyTools.GetTaxService(); //<- en rad , utan casting , lättläst ... nice ;)
</roggan>
Ok, låt oss begrunda detta påstående...
1. Vad du föreslår att använda är en typ av "lookup" pattern och det är inget fel. Man kan fritt välja lookup eller dependency injection, man kan åstadkomma samma sak men på olika sätt och det passar olika bra att använda i olika situationer...men vad jag beskrev var Dependency Injection...alltså konceptet som sådant.
2. Med ovanstående kod "return MyTaxService(params...)" så har du ju hårdkodat vilken implementation av TaxService interfacet du vill använda (MyTaxService)...och det är just det som jag har pratat om att man vill komma ifrån...har du inte läst mina inlägg ordentligt ;)
3. Du skriver "eller använd ... forName om det ska vara dynamiskt". Om vi håller oss till java så förmodar jag att du menar att skapa ett objekt med hjälp av instanceOf()...eller? Och ja, det går bra...men hur gör du om konstruktorn till MyTaxService faktiskt tar TaxDAO som parameter? Så som jag visade i mitt andra exempel...har du inte läst det ;)? Du KAN INTE då använda instanceOf() eftersom du då erhåller ett objekt som skapats med default konstruktorn, dvs utan parametrar. För att göra det tvingas du att använda reflection och bygga dig ett eget litet verktyg som kan göra det åt dig.
4. Tycker att det är lite ugly med ditt exempel där man måste lägga till en ny metod för varje ny Service man vill hämta ut från din MyTools klass. Bättre att i så fall ha en metod som t ex heter getObject("myKey") och som returnerar Object så slipper man lägga till en ny metod för varje nytt objekt man lägger till. Man måste casta objektet men det blir i alla fall snyggare och mer dynamiskt.
5. Apropå ditt exempel:
<code>
String className = someUtil.getImplementation("TaxDAO.class");
Class clazz = Class.forName(className);
Class[] daoParam = {String.class};
Constructor daoCon = clazz.getConstructor(daoParam);
Object[] dcParam = {"some/file/path.txt"};
TaxDAO taxDAO = (TaxDAO)daoCon.newInstance(dcParam);
className = someUtil.getImplementation("TaxService.class");
clazz = Class.forName(className);
Class[] srvParam = {TaxDAO.class};
Constructor srvCon = clazz.getConstructor(srvParam);
Object[] scParam = {taxDAO};
TaxService taxService = (TaxService)srvCon.newInstance(scParam);
</code>
DÄR har du DIN "enradare, utan casting, lättläst"...nja...knappast va? Naturligtvis kan du skapa någon trevlig utility klass för att göra detta...men denna koden, eller någon liknande (har inte orkat "debugga" den), kommer du att behöva. OCH du kommer säkerligen då också att bygga en utility som stödjer "lookup" och inte dependecy injection.
<roggan>
det var ju precis det jag beskrev i min första post , att det går att göra det med activator.createinstance eller class.forName i java. det handlar ju om 1 rad kod för att lösa detta.
</roggan>
Jag tror att jag bevisat att det INTE går att göra med en enkel createInstance() med exemplet ovan. Och tänk om du vill använda setter based injection, som ibland faktiskt är att föredra. Då måste du utöka antalet kodrader ännu mer i din utility klass.
<roggan>
det jag undrar över är vad jag har för nytta av det stora feta extra paketat med kod som man får med pico.
</roggan>
"stora feta extra paketat med kod som man får med pico". "Stort, fett och extra"...ja, ja...allt är relativt. Pico innehåller ett 50-tal klasser och interface. Och tycker du att det är "stort, fett och extra" så undrar jag vilken typ av applikationer eller projekt som du medverkar i...jag tycker egentligen att det är en ganska liten kodbas. Och .jar filen är på 56 KB...inte särskilt "stort, fett och extra" va? Du kanske ska ta och gå in och läsa lite mer om Pico så slipper jag återge all dess funktionalitet utöver Dependency Injection här. Temat är INTE Pico, använder den bara som ett exempel, temat är Dependency Injection.
<roggan>
eftersom "nyckeln" som används för att plocka ut den dynamiskt byggda klassen ut pico containern är hårdkodad så kan jag ju ersätta den raden med ett typat metodanrop , så jag slipper castning och det blir lättläst.
i den metod som jag nu anropar istället kan jag ju byggaihop mitt objekt hur jag vill ,
tex:
* hårdkoda.
* dynamiskt via .net activator.createinstance, java class.forName(..), vb/script createobject
</roggan>
Ok, som jag skrev i mitt första inlägg så är det ju just hårdkodningen man vill komma ifrån...är inte det ganska uppenbart nu? Dynamiskt utan parametrar till konstruktorer ja, och dynamiskt utan setter based Dependency Injection ja. Se kodexmplet från ovan.
<roggan>
jag tror jag är med på när DI är bra att använda .. dock tror jag dina exempel var lite för små för att DI ska vara bättre än något annat..
</roggan>
Kul att du "kommit på det". Om mina exempel var för små...tja...hade jag skrivit stora exempel kanske en massa andra personer inte hade fattat. Tror att det är bättre att börja smått för att förstå konceptet och sedan gå vidare med hur jag skulle kunna använda det i mina lösningar. Depenedency Injection är dock inget som enbart lämpar sig för det exempel som du gav...det lämpar sig alldeles utmärkt vid mindre operationer också om man vill ha en löskopplad miljö. Jag har aldrig sagt att Dependency Injection är bättre än något annat. Jag har aldrig påstått att det är en magisk "silver bullet" som kommer att förändra ditt liv. Det är helt enkelt bara ett alternativt sätt att se till att du får ett löskopplat system som är enkelt att underhålla, jag bara presenterade konceptet. Det är situationen man befinner sig i som säger om det är lämpligt eller inte. Ibland är Lookup patterns bra och ibland blir de bara krångliga och räcker inte till och ibland kan man tom nöja sig med hårdkodning.
<roggan>
men i Nils fall med en service klass och olika varianter av dao klasser så får jag nog säga att det känns väldigt overkill.
</roggan>
Om du tittar på exemplet jag gav dig tidigare så ser du vad alternativet kan vara. Jag använder då hellre en färdig produkt som ger mig möjligheter att skapa ett löskopplat system. Använder en annan Container till just detta + plus en massa annat i vårt nuvarande projekt och både jag och utvecklarna älskar det. Overkill eller inte...vi löser ju våra problem på ett väldigt enkelt sätt...vad mer kan man önska?
/NilsSv: Dependency Injection/Inversion of Control
man fick intrycket av att du endast använde det för att dynamiskt tilldela rätt typ av dao klass till din taxservice klass.
och det var utifrån dom exemplen som jag argumenterade för att createinstance fungerade lika bra utan 3e parts lib.
där av enrads exemplet som gjorde precis det. (och det får du ju basha och förlöjliga hur mycket du vill .. fungerar gör det och är mindre och smidigare än det exempel som fanns i din första post)
de inlägg vi gjort i den här tråden är ju absolut inte för att bråka om något utan bara för att se varför pico/IoC/DI kan vara användbart och de exempel du gav visade inte styrkan med det.
<b>
5. Apropå ditt exempel:</b>
String className = someUtil.getImplementation("TaxDAO.class");
Class clazz = Class.forName(className);
Class[] daoParam = {String.class};
Constructor daoCon = clazz.getConstructor(daoParam);
Object[] dcParam = {"some/file/path.txt"};
TaxDAO taxDAO = (TaxDAO)daoCon.newInstance(dcParam);
className = someUtil.getImplementation("TaxService.class");
clazz = Class.forName(className);
Class[] srvParam = {TaxDAO.class};
Constructor srvCon = clazz.getConstructor(srvParam);
Object[] scParam = {taxDAO};
TaxService taxService = (TaxService)srvCon.newInstance(scParam);
<b>DÄR har du DIN "enradare, utan casting, lättläst"...nja...knappast va?</b>
näe det var inte lättläst , men så var det inte min kod heller...
[edit]
för att visa för nisse hur det går att lösa det här utan att använda nisses kladdkod ovan så finns det nu ett exempel i nästa post....
[/edit]
//Roger
Sv: Dependency Injection/Inversion of Control
public class TaxService
{
private ITaxDAO dao= null;
public MyTaxService() //<-- inga params
{
dao = (ITaxDAO)Activator.CreateInstance (mysettings.assembly,mysettings.class);
}
public double calculateTax(double income, String municipal)
{
double tax = dao.findTax(municipal);
return income * tax;
}
}
public class NissesTextFilsDAO : ITaxDAO
{
private string filePath = null;
public NissesTextFilsDAO () //<-- inga params
{
filePath = mysettings["filepath"];
}
... impelmentering ...
}
public class NissesDatabasDAO : ITaxDAO
{
private string connectionString = null;
public NissesDatabasDAO () //<-- inga params
{
connectionString = mysettings["connectionstring"];
}
... impelmentering ...
}
och för att använda det hela med RÄTT typ av dao klass så gör jag
TaxService t= new TaxService(); //<-- en rad , lättläst , nice ;)
dynamiskt? ja
klarar olika config params? ja
//Roger
Sv: Dependency Injection/Inversion of Control
<roggan>
det jag och Andreas undrade över var vad kontainern fyllde för funktion och med dina exempel så framgick det inte hur och varför det var bra att använda pico.
man fick intrycket av att du endast använde det för att dynamiskt tilldela rätt typ av dao klass till din taxservice klass.
</roggan>
Ja, och det var precis vad jag gjorde så det har du uppfattat rätt. Det funkar ju alldeles utmärkt. Men det är också bara ETT användningsområde, jag kunde ha visat flera men syftet var bara att visa just konceptet. Är du med?
<roggan>
och det var utifrån dom exemplen som jag argumenterade för att createinstance fungerade lika bra utan 3e parts lib.
där av enrads exemplet som gjorde precis det. (och det får du ju basha och förlöjliga hur mycket du vill .. fungerar gör det och är mindre och smidigare än det exempel som fanns i din första post)
</roggan>
Men createInstance() fungerar ju inte i ett sådant exempel som jag senare gav dig, jag håller med om att det första inte var så bra men jag har ju gått vidare med det...har du fortfarande inte läst det eller det inlägg som du nu har kommenterat? Mer om detta längre ner.
Basha och förlöjliga? Allvarligt talat...klarar du inte av lite av den typen av höfttacklingar bör du fundera på vad du gör i ett forum. Jag kan ta gliringar till en viss del, som från dig, men när du fortfarande inte uppdaterar dina exempel efter de nya förutsättningar som jag givit, och som du eferfrågat, utan fortsätter argumentera om det gamla och sämre exemplet så får du ju räkna med sådant. Men om du tagit illa upp av mina gliringar till dig så ber jag om ursäkt.
<roggan>
de inlägg vi gjort i den här tråden är ju absolut inte för att bråka om något utan bara för att se varför pico/IoC/DI kan vara användbart och de exempel du gav visade inte styrkan med det.
</roggan>
Jag tycker nog att det senare exemplet visade styrkan och konceptet men jag vet att det kan vara svårt att förstå ett omvänt pattern mot det Lookup pattern som du kör dina exempel med. Hur det är användbart och när är väl mer upp till dig som utvecklare att bestämma. Nu vet du i alla fall att det finns.
<roggan>
näe det var inte lättläst , men så var det inte min kod heller...
</roggan>
Nä det var inte lättläst...det var ju det som var syftet...förstod du inte det? Skrev jag inte det ganska tydligt? Syftet var att visa hur enkelt det var med pico eller ett annat bibliotek för att lösa det.
Och nä, det var inte din kod...för din kod fungerar inte, inte ens i närheten, i de exempel som jag har gett. Mer om detta längre ner.
<roggan>
för att visa för nisse hur det går att lösa det här utan att använda nisses kladdkod ovan så finns det nu ett exempel i nästa post....
<roggan>
Ja det var kladdkod...men det var ju också syftet att visa JUST DET. Läs mina inlägg ordentligt så slipper vi den upprepningen i all oändlighet och som bara egentligen förstör tråden.
Jag känner dig inte så väl så sluta kalla mig "nisse", Nils går alldeles utmärkt. Det är beklämmande att se att du försöker förlöjliga mig genom att skriva ett smeknamn och dessutom bara med gemener...bah. Du är säkert jätteduktigt, men att försöka smäda mig offentligt bevisar inte det...håll dig till saken.
<roggan>
för att visa för nisse hur det GÅR att lösa det hela med de exempel jag gett så kommer det lite kod här.
</roggan>
Det här blir spännande...
<roggan> (med vissa editeringar så att det inte tar så stor plats)
<code>
public class TaxService {
private ITaxDAO dao= null;
public MyTaxService() { //<-- inga params
dao = (ITaxDAO)Activator.CreateInstance (mysettings.assembly,mysettings.class);
}
public double calculateTax(double income, String municipal) {
double tax = dao.findTax(municipal);
return income * tax;
}
}
public class NissesTextFilsDAO : ITaxDAO {
private string filePath = null;
public NissesTextFilsDAO () {
filePath = mysettings["filepath"];
}
... impelmentering ...
}
public class NissesDatabasDAO : ITaxDAO {
private string connectionString = null;
public NissesDatabasDAO () //<-- inga params
{
connectionString = mysettings["connectionstring"];
}
... impelmentering ...
}
</code>
och för att använda det hela med RÄTT typ av dao klass så gör jag
<code>
TaxService t= new TaxService(); //<-- en rad , lättläst , nice ;)
</code>
</roggan>
Och återigen har du använt dig av mitt namn på ett löjligt sätt...ett billigt psykologiskt trick för att få folk att inrikta sig på personen du argumenterar med och inte på saken. Är detta för att din argumentation kanske inte längre håller och du inte vill att andra ofentligt ska se hur genomskinlig den är? Jag tror/hoppas att de flesta ser igenom det där så ett tips, inrikta dig på sakfrågan istället.
Men ok, låt oss dissekera det här...tillbaka till exemplet jag gav...inte det första, det hade vissa brister kan jag erkänna, utan koncentrera mer på det andra.
1. TaxService är INTE en konkret klass. Däremot var MyTaxService en konkret klass så redan där blir det fel i ditt exempel ovan. Jag använde TaxService.class som nyckel för att få tillbaka en implementation, dvs MyTaxService. Det är väl ganska tydligt.
2. Jag ändrade konstruktorn i MyTaxService till att ta ett argument MyTaxService(TaxDAO dao) för att få en mer öppen design och för att inte behöva förlita sig på en IOC funktion eller den som du har i din implementation. Jag vill alltså INTE ha "<-- inga params". Det har du inte gett något exempel på hur du löser. Konstruktorer med argument...alltså "Constructor based Dependency Injection". Och tänk om en annan implementation av TaxService tar två argument i sin konstruktor eller att en annan tar tre...det har du inte heller varit i närheten av att visa med dina exempel hur du ska sköta det dynamiskt.
3. Samma sak som punkt två. Jag ändrade konstruktorn i TxtTaxDAO till att ta en String som argument. Om jag skulle skriva DBTaxDAO så kanske den konstruktorn skulle ta två argument. Och jag vill inte lösa det som du har gjort med en helt stängd design utan jag vill ha de argumenten i konstruktorn. Visa mig hur du gör det på ett dynamiskt sätt.
4. "Setter based Dependency Injection" (objektet injectas via en "setX(Interface i)" metod) kan ibland vara att föredra framför Constructor based, visa mig hur du löser detta på det "dynamiska" sätt som du använder. Hårdkodning funkar inte så bra här kan jag upplysa dig om.
<roggan>
dynamiskt? ja
</roggan>
Ja, men låst dynamiskt...och bara dynamiskt i den mening att kan skapa nya default objekt med tom konstruktor...och långt ifrån Dependency Injection.
<roggan>
klarar olika config params? ja
</roggan>
Men fortfarande inte i närheten av att vara dynamiskt på det sätt som Dependency Injection och t ex Pico.
Om du vill svara på detta inlägg så se till att få dina exempel rätt, alltså baserade på scenarios jag givit här, så kan vi diskutera vidare därifrån.
/NilsSv: Dependency Injection/Inversion of Control
men men , om vi fortsätter
<b>Men fortfarande inte i närheten av att vara dynamiskt på det sätt som Dependency Injection och t ex </b>
nej det är jag helt med på ,
men om vi bara ser till _vad_ som skulle göras och inte _hur_ det ska göras så var ju kraven något i stil med.
<i>
* kunna skapa en instans av taxservice som är initierad med en taxdao specad i någon form av config
* varje specifik taxdao implementation ska kunna ha sin egen uppsättning config params ... eg constr , filepath etc.
* bonus: det ska gå att hämta sin taxservice på ett så snyggt sätt som möjligt
</i>
där är kravspecen så som jag ser det .. _hur_ det implementeras är valfritt.
i ditt senare exempel valde du att ta eventuella config params via construktorn på dina implementeringar , vilket _inte_ såg ut att vara ett _krav_ för det scenario som beskrevs utan snarare ett val för att få en mer återanvändbar modell.
du skriver själv : "Detta är en bättre design av klassen, att ta TaxDAO som argument i konstruktorn"
vilket jag tar som ett val _hur_ du valt att lösa det , inte ett av kraven för _vad_ som ska lösas.
så med dessa förutsättningar resonerar jag att
går det att lösa samma sak själv utan att skriva massor av egen kod så gör jag gärna det ,
då slipper jag ansvara för kod som någon annan skrivit och
är det mycket kod och jobbigt att sätta sig in i så kan man bli beroende av att leverantören fixar eventuella buggar... skulle dessa buggar upptäckas i en livemiljö av min applikation och jag är beroende av 3epart som kanske inte svarar på supportfrågor så sitter man i klistret..
därför skulle jag i ett fall som detta valt att inte använda 3eparts libbet och löst det själv.
du säger även att om klasserna har flera olika constructors så fungerar inte min lösning.
nej om kravet är att det ska vara olika constructors så visst. men om vi utgår från den kravspec som vi har ovan (vad som ska göras inte hur .. om du är med på att det är det som gäller)
så kan jag precis lika lätt lösa det genom att kolla om vissa confignycklar är specade inne i min defaultconstructor och beroende på dessa välja att skapa rätt childobjekt.
kanske inte lika rent och löskopplat men likväl skulle det fungera och i ett litet scenario så kan det vara
att föredra mot att blanda in massa mer extra kod.
mer kod = mer potentiella buggar.
mer kod som någon annan buggfixar = kunder _kan_ få dras med buggar en längre tid än annars.
oke jag slog kanske världsrekord i underscorade ord nu men vaffan ;-P
//Roger
för att förtydliga:
<b>1. TaxService är INTE en konkret klass. Däremot var MyTaxService en konkret klass så redan där blir det fel i ditt exempel ovan. Jag använde TaxService.class som nyckel för att få tillbaka en implementation, dvs MyTaxService. Det är väl ganska tydligt. </b>
det kan man lösa med den dynamiska factory metod som jag visade i andra posten.
alltså :
ITaxService t=GetTaxService();
där gettaxservice dynamsikt skapar rätt taxservice implementation baserat på nycklar i configgen
<b>2. Jag ändrade konstruktorn i MyTaxService till att ta ett argument MyTaxService(TaxDAO dao) för att få en mer öppen design och för att inte behöva förlita sig på en IOC funktion eller den som du har i din implementation. Jag vill alltså INTE ha "<-- inga params". Det har du inte gett något exempel på hur du löser. Konstruktorer med argument...alltså "Constructor based Dependency Injection". Och tänk om en annan implementation av TaxService tar två argument i sin konstruktor eller att en annan tar tre...det har du inte heller varit i närheten av att visa med dina exempel hur du ska sköta det dynamiskt.
</b>
som jag skrev ovan så går det att lösa genom att kolla vilka nycklar som är specade ..
jag kan få samma beteende genom att göra:
public MyTaxService()
{
if (mysettings["bla"]!=null && mysettings["blö"]!=null)
{
//gör samma sak som du skulle gjort i din konstruktor med två params
}
else if (mysettings["kamel"]!=null && mysettings["isbjörn"]!=null)
{
//gör samma sak som du skulle gjort i en annan konstruktor med två andra params
}
else if (mysettings["kamel"]!=null )
{
//gör samma sak som du skulle gjort om bara "kamel" var specad i configgen
}
}
som jag sa tidigare , det är inte lika snyggt eller löskopplat men det löser precis samma saker.
eftersom pico kommer utföra i princip samma ifsatser och välja rätt konstruktor utifrån vilka nycklar som reggats.. därför är det möjligt att lägga motsvarande logik i defaultkonstruktorn..
Sv: Dependency Injection/Inversion of Control
ok jag ber om ursäkt för eventuella bitchslaps men blev lite irriterad när du postade något som "min" kod när jag aldrig varit i närheten av att förespråka den koden du postade..
</roggan>
Har jag aldrig gjort iofs men ursäkten är godtagen.
<roggan>
nej det är jag helt med på ,
men om vi bara ser till _vad_ som skulle göras och inte _hur_ det ska göras så var ju kraven något i stil med.
</roggan>
Men kom igen...det var ju precis det som det här inlägget handlade om...HUR något skulle göra och inte VAD. Jag tror att du har missat poängen med inlägget.
<roggan>
<i>
* kunna skapa en instans av taxservice som är initierad med en taxdao specad i någon form av config
* varje specifik taxdao implementation ska kunna ha sin egen uppsättning config params ... eg constr , filepath etc.
* bonus: det ska gå att hämta sin taxservice på ett så snyggt sätt som möjligt
</i>
där är kravspecen så som jag ser det .. _hur_ det implementeras är valfritt.
</roggan>
Nej det var inte valfritt :) Jag vill fortfarande att du visar mig kod som fungerar där du skapar en TaxService som implementeras av MyTaxService och som tar TaxDAO som konstruktor argument. TaxDAO ska implemetneras av TxtTaxDAO som tar en String som input parameter i konstruktorn...det är något som du fortfarande åstadkommit. Sedan kan du ta och visa ett exempel med setter based injection också när du ändå är på g :)
<roggan>
i ditt senare exempel valde du att ta eventuella config params via construktorn på dina implementeringar , vilket _inte_ såg ut att vara ett _krav_ för det scenario som beskrevs utan snarare ett val för att få en mer återanvändbar modell.
du skriver själv : "Detta är en bättre design av klassen, att ta TaxDAO som argument i konstruktorn"
vilket jag tar som ett val _hur_ du valt att lösa det , inte ett av kraven för _vad_ som ska lösas.
</roggan>
Jo det är krav...som sagt, visa mig hur du gör :)
<roggan>
du säger även att om klasserna har flera olika constructors så fungerar inte min lösning.
nej om kravet är att det ska vara olika constructors så visst.
</roggan>
Och då har du erkännt att din lösning inte håller så då behöver jag inte heller längre några bevis. Dependency Injection handlar om just Constructor Based Injection, Setter Injection och Inerface Injection och det går inte att lösa på ditt sätt. Bra att du erkänner det till slut trots att det satt lång inne. ;) Men en sak har du haft rätt i hela tiden...mitt första exempel var kass.
<roggan>
men om vi utgår från den kravspec som vi har ovan (vad som ska göras inte hur .. om du är med på att det är det som gäller)
så kan jag precis lika lätt lösa det genom att kolla om vissa confignycklar är specade inne i min defaultconstructor och beroende på dessa välja att skapa rätt childobjekt.
</roggan>
Som sagt...den kravspecen invalidiserades efter jag kommit med mitt andra inlägg. Det är ingen vacker design att alltid låta instansieringen av objekt ske på det låsta sättet...men ibland funkar det bra...och ibland funkar det sämre...och när det funkar sämre har man alltid t ex Pico att tillgå, och har man redan Pico i projektet kan man se till att vara konsekvent och alltid använda den.
<roggan>
kanske inte lika rent och löskopplat men likväl skulle det fungera och i ett litet scenario så kan det vara
</roggan>
Som sagt...och som du sa tidigare...det skulle inte fungera i det öppna scenario som jag beskrev...och som ju faktiskt var själva grejen.
<roggan>
det kan man lösa med den dynamiska factory metod som jag visade i andra posten.
alltså :
ITaxService t=GetTaxService();
där gettaxservice dynamsikt skapar rätt taxservice implementation baserat på nycklar i configgen
<roggan>
Men så använder du återigen den stängda designen.
<roggan>
public MyTaxService()
{...}
{
if (mysettings["bla"]!=null && mysettings["blö"]!=null)
{...}
{
//gör samma sak som du skulle gjort i din konstruktor med två params
}
else if (mysettings["kamel"]!=null && mysettings["isbjörn"]!=null)
{...}
{
//gör samma sak som du skulle gjort i en annan konstruktor med två andra params
}
else if (mysettings["kamel"]!=null )
{...}
{
//gör samma sak som du skulle gjort om bara "kamel" var specad i configgen
}
}
</roggan>
Men det där måste väl ändå betraktas som en väldigt dålig design...är det verkligen du som har kodat det där ;) Urk...
<roggan>
som jag sa tidigare , det är inte lika snyggt eller löskopplat men det löser precis samma saker.
</roggan>
Det löser kanske samma saker med handpåläggning för varje förändring...och det är som sagt riktigt, riktigt ugly.
<roggan>
eftersom pico kommer utföra i princip samma ifsatser och välja rätt konstruktor utifrån vilka nycklar som reggats.. därför är det möjligt att lägga motsvarande logik i defaultkonstruktorn..
</roggan>
Pico kommer inte att vara i närheten av dessa if-satser som du har...Pico jobbar med Reflection (vet inte om du jobbat något med det?)...rent och snyggt och väldigt dynamiskt och flexibelt.
Så "logiken" i konstruktorn ovan är INTE något som i närheten motsvarar Pico. Och tänk dig att du har en ca 500 klasser som du ska ha sådana konstruktorer i...snacka om spaghetti.
/NilsSv: Dependency Injection/Inversion of Control
<b>Har jag aldrig gjort</b>
i vilket av mina inägg låg den kod du visade som "min" ??
om du tror att det var så jag menade så har du fattat fel.
<b>Men kom igen...det var ju precis det som det här inlägget handlade om...HUR något skulle göra och inte VAD. Jag tror att du har missat poängen med inlägget.</b>
näe , du visade en lösning som både jag och Andreas ansåg vara overkill för ett så litet scenario som du visade... även när du införde constructorer så skulle det i det lilla exemplet gått att lösa smidigare.
<b>. Och tänk dig att du har en ca 500 klasser som du ska ha sådana konstruktorer i...snacka om spaghetti</b>
jag skrev att i ett <b>litet scenario</b> där man bara vill göra det du beskrev i ditt exempel kan det vara att föredra att INTE använda ett 3eparts libb om jag kan lösa samma saker med lite kod
och de saker du beskrev i dina exempel GÅR att lösa som jag beskrivit.
<b>Nej det var inte valfritt :) Jag vill fortfarande att du visar mig kod som fungerar där du skapar en </b>
nej men då pratar vi bevisligen om olika saker och kan avsluta det här rakt av.
jag argumenterade för en lösning på problemet med att i runtime välja rätt implementation, du argumenterar för att min lösning inte ser ut som din lösning.
<b>Som sagt...och som du sa tidigare...det skulle inte fungera i det öppna scenario som jag beskrev...</b>
som sagt mina exempel KAN lösa den problematik du beskrivit i dina exempel.
om du sedan vill argumentera för att det inte är löst på samma sätt så är det ju ditt problem.
<b>Pico kommer inte att vara i närheten av dessa if-satser som du har</b>
nej självklart inte men fortfarande , i det lilla exempel (inte i andra stora) så går det lösa problemet med väldigt lite kod.
så kort o gott det jag säger är att i det lilla exempel du gav så skulle mina exempel lätt kunna lösa de krav som _jag_ uppfattat utifrån dina exempel.
om dina krav är att koden ska designas på ett visst sätt så pratar vi om olika saker.
hela ide'n måste väl vara att man ska använda pico för att det finns ett problem som ska lösas . inte att man ska skriva kod på ett visst sätt bara för att pico finns?
//Roger
btw. någon som tror att manpower kursar snart?Sv: Dependency Injection/Inversion of Control
<roggan>
du visade en lösning som både jag och Andreas ansåg vara overkill för ett så litet scenario som du visade... även när du införde constructorer så skulle det i det lilla exemplet gått att lösa smidigare.
</roggan>
Och nej...du har inte visat hur du skulle lösa det. Du löser det fortfarande inte med alla dina if-satser...tyvärr. Du tvingas hårdkoda mm och når inte den dynamik som jag tidigare beskrivit...du gör faktiskt inte det. Och smidigare...if else if else if else if else if...är det smidigt...nu skojar du. Och återigen...försök blicka lite längre och häng inte upp dig på ett ETT exempel...ibland måste man tänka vidare själv.
<roggan>
jag argumenterade för en lösning på problemet med att i runtime välja rätt implementation, du argumenterar för att min lösning inte ser ut som din lösning.
</roggan>
Nä, men du implemeterar inte enligt spec...som sagt du har fortfarande inte visat något som FUNGERAR eller som är SMIDIGT. Och din lösning får se ut hur som helst, jag bryr mig allvarligt talat inte. Jag har beskrivit en teknik...du säger att det går att lösa på annat sätt...jag borde ha stoppat diskussionen där, för det var inte det som det handlade om. Jag argumenterar inte för något, bara informerar...allt jag säger är att din lösning inte fungerar. Och jag har sagt flera gånger att detta inte är någon "silver bullet" utan bara ett annat sätt att lösa ett problem.
<roggan>
som sagt mina exempel KAN lösa den problematik du beskrivit i dina exempel. om du sedan vill argumentera för att det inte är löst på samma sätt så är det ju ditt problem.
</roggan>
Men visa att de kan det då...för du har FAKTISKT inte gjort det hittills. Och återigen...det här handlar om ett koncept och inte om ett enkelt exempel...suck.
<roggan>
nej självklart inte men fortfarande , i det lilla exempel (inte i andra stora) så går det lösa problemet med väldigt lite kod.
</roggan>
Men igen är du på exemplet...tänk lite större är du snäll. Är det bara just exemplet du har hackat på så är all tid jag lagt ner på att konversera med dig helt bortkastad.
<roggan>
så kort o gott det jag säger är att i det lilla exempel du gav så skulle mina exempel lätt kunna lösa de krav som _jag_ uppfattat utifrån dina exempel.
</roggan>
Menar du att du löser det med dina if-satser? Kort och gott...det gör du inte...och du är på exemplet en gång till...phu...
<roggan>
om dina krav är att koden ska designas på ett visst sätt så pratar vi om olika saker.
</roggan>
Det är vad jag pratat om hela tiden och med ett riktigt exempel från och med mitt andra inlägg...så du har nog inte läst mina svar alltför noggrannt. Å andra sidan gnäller du på exemplet hela tiden, konstigt.
<roggan>
hela ide'n måste väl vara att man ska använda pico för att det finns ett problem som ska lösas . inte att man ska skriva kod på ett visst sätt bara för att pico finns?
</roggan>
Precis...och det har jag sagt hundratals gånger det också...börjar bli trött på att upprepa mig.
Den här var ändå bäst:
<roggan>
i vilket av mina inägg låg den kod du visade som "min" ??
om du tror att det var så jag menade så har du fattat fel.
<roggan>
Är inte det här din kod? I alla fall är den postad 2004-09-02 16:18:14 av Roggan i denna tråden...
<roggan>
<code>
public MyTaxService()
{...}
{
if (mysettings["bla"]!=null && mysettings["blö"]!=null)
{...}
{
//gör samma sak som du skulle gjort i din konstruktor med två params
}
else if (mysettings["kamel"]!=null && mysettings["isbjörn"]!=null)
{...}
{
//gör samma sak som du skulle gjort i en annan konstruktor med två andra params
}
else if (mysettings["kamel"]!=null )
{...}
{
//gör samma sak som du skulle gjort om bara "kamel" var specad i configgen
}
}
</code>
</roggan>
Och den ÄR faktiskt helt vansinnig.
Nåväl...det du verkar ha hängt upp dig på är mitt exempel, du nämnde det ungefär fem gånger hur litet mitt exempel var, och inte själva idén...suck...det gör mig faktiskt lite bedrövad. Så om man ska publicera ett inlägg här så ska det vara i bokformat...ok, ska försöka komma ihåg det nästa gång. Och du har inte visat ett enda exempel hur du löser det problem som jag gav, öppen design med parametrar i konstruktorn. Läs på om Reflection, där har du lösningen. Och igen...jag har inte sagt att detta är någon "silver bullet" utan bara ett annat sätt att lösa ett problem på. Använd din lösning om du vill istället...jag skiter i vilket. Tycker att den här tråden är avslutad nu...har varit mycket tjafs om ingenting uppenbarligen...men alla har nog lärt sig något i alla fall.
/NilsSv: Dependency Injection/Inversion of Control
därefter postar du någon jävla gägg kod och skriver att det var min kod.. vem som hellst kan kolla att jag aldrig föreslagit den koden , det var du och ingen annan som skrev den har du problem att skilja på fantasi och verklighet så finns det säkert undersökningar du kan få.
därefter svarar du att jag visst skrivit koden och refererar till annan kod som ingick i ett senare inlägg.
koden med ifsatserna var för att visa att det faktiskt går att få samma beteende som men flera constructors , om du har svårt att greppa påhittade nyckelvärden så kan du få ett nytt exempel som kanske är lättare att förstå för dig
if (mysettings["LogServiceClass"]!=null)
{
//skapa en instans av någon form av logg
}
vilket skulle ge sama funktionallitet som om du i pico har en constructor som tar en logservice klass.
<b>Läs på om Reflection, där har du lösningen.</b>
jo jag är väl medeten om hur reflection fungerar , skriver för närvarande en egen kompilator för ett testspråk i .net
du är nog den drygaste jävla stålle jag stött på här , jag tycker du ska ransaka dig själv och fundera över varför du lyckats göra dig obekväm med varenda person du haft kontakt med på den här sajten på bara några få veckor.
du rycker friskt snuttar av text här och där och vrider o vänder på för att kunna ge något löjligt svar och blir du överbevisad så ändrar du förutsättningarna på det vi pratade om tills det passar bara dig:
du började med ett exempel där man dynamiskt skulle kunna välja dao implementation.
du fick en alternativ lösnining på det som faktsikt fungerar.
då ändrades förutsättningarna till att den ena dao implementationen skulle minsann ta en parameter som säger vart en viss fil ska ligga..
då fick du en annan lösning som även den fungerade fint , även om den inte vär löskopplad , men fungerar gör den..
då blir förutsättningarna helt plötsligt att om vi har 500!!! objekt istället för en serviceklass och två childklasser...
nee , nu avslutar jag det här..
tack o gonatt
//RogerSv: Dependency Injection/Inversion of Control
Nu får du väl ändå ta och skärpa dig "Roggan".
Jag har inte lagt mig i diskussionerna som varit eller den som går nu heller men jag läser dem. Tycker det är intressant och lärande. Nils har alltid bra argument och är mycket bra för er på Denna site.
Varför är han det då?
Jo för att han väcker er som är så jävla insnöad på .NET och sitter och sli**** varandra i r***** på denna site. Normen har skrivit om blaj som står oftast identiskt i någon Fowler bok eller så är det bara fel.
Vakna och se dig omkring.Sv: Dependency Injection/Inversion of Control
Lite väl lösryckt va? Roggan påpekade Nils sätt att argumentera och framföra en åsikt - inte .NET vs. Java eller något annat, så vad har det med saken att göra?Sv: Dependency Injection/Inversion of Control
Tackar för de ödmjuka komplimangerna :-) Men dock kan jag inte hitta mkt av det jag publicerat som tagits ur någon Fowler bok, dock har jag reffererat till hans böcker då han som många andra tar upp saker kring
ämnet. Att ge refferenser tycker jag är en viktig bit för att få andra att söka information vidare.
"Normen har skrivit om blaj som står oftast identiskt i någon Fowler bok eller så är det bara fel."
Om jag skrivit nått som är fel, kan inte du då starta en diskusion om det? det är det som är syftet med mina inlägg, jag drar upp nått som jag tycker verkar intressant eller kan ses som intressant ur min synvinkel eller ur någon annans av den anledningen att jag vill FÖRA en diskussion. Brukar oftast om inte alltid avsluta med vad har ni för erfarenheter? vad ser ni på detta? vad tycker ni? för att JUST få igång ett intresse. Jag är långt från bäst, jag har idéer jag har tankar jag publicerar dem, många är nöjda med dem, andra mindre nöjda och somliga klandrar dem. Skit kul så länge man har något konstruktivt att säga.
Jag vill oxå lära mig.
"Jo för att han väcker er som är så jävla insnöad på .NET och sitter och sli**** varandra i r***** på denna site. "
Om du inte förstått det är .Net ett verktyg. Att då använda det verktyg man behärskar bäst i sina exempel och argument anser inte jag vara något slickeri... Så jag antar att du gillar Java eller nått anant språk bättre? Slickar du en massa då oxå? Förstår inte, förklara snälla. Vilket är ert huvudspråk på Högskolan du går på? Tittar ni på olika språk? vilket gillar du bäst av dem du vart i kontakt med? och varför? Då även forumen heter .Net Arkitektur, eller ASP .Net är det ju svårt att svara med Java kod. Tycker du inte? finns ingen logik i det.
Mvh JohanSv: Dependency Injection/Inversion of Control
vad menar du med slickar varandra i röven?
jag och Johan (och andra) har väl diskuterat saker otaliga gånger med olika åsikter.
dock är det alltid bra stämning när tråden avslutas och oftast så köper båda sidor varandras argument till viss del.
i fallet med nisse så är det inte alls så.
om en normal person publicerat ett inlägg som nisses första och sedan fått ett svar att samma sak går att göra med en provider lösning så skulle den normalt funtade personen svara ödmjukt att "ja det går men i ett scenario med många fler objekt är IoC bra därför att blablabla"
så gör dock inte nisse , han vrider och vänder istället på förslagen för att få dom att framstå som korkade i sina NYA scenarion för att på så sätt göra sig lite rolig.
//RogerSv: Dependency Injection/Inversion of Control
Vi börjar med Roggan.
<roggan>
jag tror fan du är autistisk
</roggan>
Det tror fan inte jag. Och jag avskyr verkligen när folk börjar komma med personangrepp av denna typ. Hur lågt kan man egentligen sjunka? Tydligen hur lågt som helst. Men det är ju så det funkar när argumenten tryter...sista vapnet är at angripa personen...och då vet man ofta själv också att slaget är förlorat.
<roggan>
du gav ett exempel , jag gav en lösning på problemet , vem som hellst kan ta koden i mina exempel och kompilera och köra och se att dom fungerar fint för det scenario med taxservice som du gav. hur gärna du än vill att den inte ska fungera så fungerar nisseklasserna och gör precis det dom ska...
</roggan>
Och du fortsätter fortfarande att prata om det första exemplet. Läs första inlägget från mig...där står klart och tydligt "Det här var bara ett enkelt test och exempel" ...men det är tyvärr exemplet som du sedan hakar upp dig på och inte själva poängen. Jag har sagt att du ska bortse från det och titta på det andra med konstruktorer från och med mitt andra inlägg...och nej, du har inte gett en lösning som fungerar. Dina "nisseklasser" gör inte det som jag beskrev att Dependency Injection löser...och det är ju det som det handlar om. Du får hemskt gärna lösa dina bekymmer med nästlade if-satser i all evighet men det är liksom inte riktigt syftet...men jag vet inte om du förstår det?
<roggan>
därefter postar du någon jävla gägg kod och skriver att det var min kod
</roggan>
Jag har aldrig skrivit att det explicit var DIN kod...kan du inte läsa mellan raderna? Det är så man måste göra om man vill få ett liknande beteende som finns i Pico...phu.
<roggan>
vem som hellst kan kolla att jag aldrig föreslagit den koden, det var du och ingen annan som skrev den har du problem att skilja på fantasi och verklighet så finns det säkert undersökningar du kan få.
</roggan>
Och återigen ett personangrepp...suck...så lågt. Om du inte kan argumentera för dig, med sakliga argument, bör du nog fundera på att inte argumentera alls. För övrigt se svaret ovan.
<roggan>
koden med ifsatserna var för att visa att det faktiskt går att få samma beteende som men flera constructors , om du har svårt att greppa påhittade nyckelvärden så kan du få ett nytt exempel som kanske är lättare att förstå för dig
</roggan>
Det gör det faktiskt inte. Du löser inte det. Och om det skulle fungera hur snyggt hade det varit? Inte ens du kan själv tycka att det är bra kod oavsett om den befinner sig i ett projekt som innehåller 50 eller 500 klasser.
<roggan>
du är nog den drygaste jävla stålle jag stött på här , jag tycker du ska ransaka dig själv och fundera över varför du lyckats göra dig obekväm med varenda person du haft kontakt med på den här sajten på bara några få veckor.
</roggan>
Och vi tar ett nytt personangrepp, ifall någon ännu inte förstått hur illa du tycker att du blivit behandlad här. Jag har varit med i en del diskussioner ja...och alla kanske inte tycker som mig, men jag förstår inte vad det har med den här diskussionen kring Dependency Injection att göra? Jag har fått ganska många iMail, från ganska många olika människor, där folk håller med mig men de tycker att allt är så väldigt infekterat att de inte vill lägga sig i diskussionen offentligt. Så kanske du ska ta och läsa igenom tråden igen och göra det som du föreslår mig?
<roggan>
du rycker friskt snuttar av text här och där och vrider o vänder på för att kunna ge något löjligt svar och blir du överbevisad så ändrar du förutsättningarna på det vi pratade om tills det passar bara dig
</roggan>
Och återigen det här ÄLTANDET om att jag ändrar förutsättningar. Jag har erkännt att mitt första exempel var fel så många gånger nu och att Dependency Injection är mer användbart vid det andra exemplet jag gav och vid setter based injection vilket du inte ens har kommenterat. Du har låst fast dig vid det första exemplet och ältar om att det går att lösa osv...och ja...det har du bevisat...men du har inte visat något fungerande OCH med den löskoppling som beskrivs, och som är SYFTET, med Dependency Injection. I vilket fall har du inte postat det på det här forumet.
<roggan>
du började med ett exempel där man dynamiskt skulle kunna välja dao implementation. du fick en alternativ lösnining på det som faktsikt fungerar.
</roggan>
Och så är vi där igen...det första exemplet...ja, ja...
<roggan>
då ändrades förutsättningarna till att den ena dao implementationen skulle minsann ta en parameter som säger vart en viss fil ska ligga..
då fick du en annan lösning som även den fungerade fint , även om den inte vär löskopplad , men fungerar gör den..
</roggan>
Minsann ja...det skulle den där konstruktorn minsann göra. Det var det som var syftet från början men jag missade det i mitt första exempel vilket jag sedan rättade till i mitt andra inlägg. Jag undrar om du verkligen läser mina inlägg.
En annan lösning som fungerade fint? Är det if-spasmerna som vi pratar om nu? Och nu vet jag ATT du missat poängen med det hela och Dependency Injection...för det är ju just LÖSKOPPLING och inte HÅRDKODNING som det handlar om!
<roggan>
då blir förutsättningarna helt plötsligt att om vi har 500!!! objekt istället för en serviceklass och två childklasser...
</roggan>
Men det var ett exempel...det förstår du väl själv att ett system inte bara består av en serviceklas och en dao klass? Och det med 500 var ingen förutsättning...jag ville bara att du skulle tänka på konsekvenserna av att använda dina if-satser i ett projekt av den storleken. Man måste väl kunna kräva av en läsare att de själva kan tänka längre än vad ett enkelt exempel visar?
Det var Roggan det...och nu över till de som följde efter detta. Vi börjar med Sky.
<sky>
Nu får du väl ändå ta och skärpa dig "Roggan".
</sky>
Det varfaktiskt skönt att se att det inte bara var jag som tog illa upp av de påhopp som Roggan gör. Sky är faktiskt inte en av de jag fått mail av som också tar upp dessa påhopp...men det är ändå skönt att se någon stå upp offentligt.
<sky>
Tycker det är intressant och lärande. Nils har alltid bra argument och är mycket bra för er på Denna site.
</sky>
Tackar och bugar.
<sky>
Jo för att han väcker er som är så jävla insnöad på .NET och sitter och sli**** varandra i r***** på denna site. Normen har skrivit om blaj som står oftast identiskt i någon Fowler bok eller så är det bara fel.
</sky>
Hmmm...den där var inte så bra...blev nästan lika illa Roggans påhopp. Jag tycker att vi lämnar påhopp av denna typ och de som Roggan gör helt. De hör helt enkelt inte hemma här.
Normén X 2 är bra och Johan har skärpt sitt humör oerhört så det är faktiskt riktigt trevligt att diskutera med honom...och hans bror Fredrik har alltid varit en hygglig prick. Johans blog blir bättre och bättre, det är svårt att skriva för folk när man inte vet vilken förkunskap de har...jag om någon förstår det ;), och han gör ett hästjobb här med att hjälpa folk i forumen.
Och nu över till Johans svar. Kan bara säga att ditt inlägg här var klockrent, det var riktigt bra...jag gillar att du fått kontroll på humöret ;)
Och tillbaka till Roggan...igen...sista ordet var inte sagt tydligen...
<roggan>
om en normal person publicerat ett inlägg som nisses första och sedan fått ett svar att samma sak går att göra med en provider lösning så skulle den normalt funtade personen svara ödmjukt att "ja det går men i ett scenario med många fler objekt är IoC bra därför att blablabla"
</roggan>
Och varför inte dra till med ett personangrepp igen...det börjar ju bli en typ av trademark nu. Men varför kan inte du erkänna att din lösning inte fungerar med konstruktor baserad Dependency Injection eller setter based Dependency Injection då kravet SAMTIDIGT är att lösningen ska vara totalt löskopplad? Det är ju detta som allt handlar om. Och det är det som jag vill att du ska visa, annars kan du väl visa vilket pattern som helst. Jag kan väl inte säga att "ja den fungerar" bara för sägandets skull och för att vi alla ska vara en stor lycklig familj och hålla varandra i handen? Och apropå ödmjukhet ska du nog titta igenom dina senaste inlägg och det språk du använder.
<roggan>
så gör dock inte nisse , han vrider och vänder istället på förslagen för att få dom att framstå som korkade i sina NYA scenarion för att på så sätt göra sig lite rolig.
</roggan>
Återigen roggan...det har aldrig varit några nya scenarior. Grundförutsättningarna har varit desamma sedan mit andra exempel...inget har förändrats.
Jag skrev i förra inlägget att var det sista i den här tråden...men jag bröt mitt löfte...detta blev det sista istället. Men det som jag tycker är för jävligt, rent ut sagt, är hur du Roggan fördärvat den här tråden. Du diskuterar lösningar som INTE motsvarar Dependency Injection, du säger detta själv, att ditt förslag inte löser det, på flera ställen men måste ändå diskutera in i absurdum och komma med personliga påhopp, och hela syftet med det här inlägget känns nog bortglömt för de flesta...synd...och jag kommer att tänka mig noga för innan jag postar något här igen.
/NilsSv: Dependency Injection/Inversion of Control
Nils, vore kul om du kopierade din första Artikelbit och la in den på nytt i så fall. Kan du det? För jag tycker den kan vara av nytta. Ev om du lägger till någon refferens länk om man vill läsa mera?
Tycker det är trist att det blivit så tråkig stämmning på senare tid.
Mvh Johan