[C#] Juiste interface instantiëren*

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

  • Defector
  • Registratie: December 2005
  • Niet online
Ik zit even te puzzelen hoe ik dit probleem oplos.

Ik heb een interface die door een aantal classes wordt geïmplementeerd.

Nu wil ik redelijk eenvoudig de juiste klasse aanmaken zonder daar verschil in te maken. Aangezien de implementatie mij niet uitmaakt op het moment dat ik de calls maak.

Dit zou kunnen door IoC, Dependency Injection maar is daar geen makkelijke manier voor?

Ik zou het willen oplossen door middel van een constructor. Die de juiste versie aanmaakt. Maar dat zou dan in de implementatie classes moeten. En dat is niet de juiste plek.

Beste antwoord (via Defector op 11-09-2017 12:37)


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Defector schreef op maandag 11 september 2017 @ 12:02:
En dat moment van aanmaken en de juiste implementatie teruggeven wil ik op de juiste plek uitwerken.
Nogmaals; dat lijkt me gewoon een factory.

Verder is 'een component binnenhalen' zelden nodig, maar scheelt 't je wel het wiel opnieuw uitvinden. Maar ik zie, vooralsnog, ook geen noodzaak om een IoC component binnen te halen voor zoiets simpels. Maar ik/wij heb(ben) natuurlijk niet 't complete overzicht dat jij wél hebt en kan/kunnen dat dus moeilijk beoordelen op basis van wat we nu weten.
Defector schreef op maandag 11 september 2017 @ 12:02:
Ah volgens mij haal ik IoC en DI door elkaar.
DI is een 'subset' van IoC.

[ Voor 12% gewijzigd door RobIII op 11-09-2017 12:16 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Alle reacties


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Welke taal hebben we 't over?
Defector schreef op maandag 11 september 2017 @ 11:55:
Ik zou het willen oplossen door middel van een constructor. Die de juiste versie aanmaakt.
Een constructor returned altijd het type van die klasse dus dan ben je al 'voorbij' het besluit welke implementatie je gaat gebruiken. Je wil waarschijnlijk een factory maken, maar je vraag is nogal... euh... vaag :P
Defector schreef op maandag 11 september 2017 @ 11:55:
Nu wil ik redelijk eenvoudig de juiste klasse aanmaken zonder daar verschil in te maken. Aangezien de implementatie mij niet uitmaakt op het moment dat ik de calls maak.
De "juiste klasse", "implementatie maakt me niet uit" spreekt elkaar nogal tegen... Als er een juiste is zijn er ook onjuiste en dus zal de implementatie je ook uitmaken.

Misschien moet je je vraag even wat concreter maken met een voorbeeldje ofzo.

(@topictitel: Je kunt geen interface instantiëren; je kunt een klasse die een interface implementeert instantiëren, wat ook uit je topic blijkt).

[ Voor 43% gewijzigd door RobIII op 11-09-2017 12:01 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • xFeverr
  • Registratie: Juni 2011
  • Laatst online: 10:52
Of bedoel je Dependency Injection?

Acties:
  • 0 Henk 'm!

  • Defector
  • Registratie: December 2005
  • Niet online
Haha heb het ook even snel opgeschreven.

De taal is C#.

Even een voorbeeld:

Ik heb een interface Car die bijv de methoden drive en stop heeft.

Een aantal implementaties daarvan bijv Golf, Clio, Leon

Op het ene moment van aanmaken na maakt het mij niet uit welke implementatie ik gebruik aangezien ik toch de methoden drive/stop aanroep.

En dat moment van aanmaken en de juiste implementatie teruggeven wil ik op de juiste plek uitwerken. Aangezien de implementatie daar eigenlijk weinig mee van doen heeft. Vind ik dat niet de juiste plek.
xFeverr schreef op maandag 11 september 2017 @ 12:01:
Of bedoel je Dependency Injection?
Ah volgens mij haal ik IoC en DI door elkaar. Maar zoiets moet toch ook makkelijker op te lossen zijn dan een DI component je project binnen te halen?

[ Voor 43% gewijzigd door Defector op 11-09-2017 12:06 ]


Acties:
  • Beste antwoord
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Defector schreef op maandag 11 september 2017 @ 12:02:
En dat moment van aanmaken en de juiste implementatie teruggeven wil ik op de juiste plek uitwerken.
Nogmaals; dat lijkt me gewoon een factory.

Verder is 'een component binnenhalen' zelden nodig, maar scheelt 't je wel het wiel opnieuw uitvinden. Maar ik zie, vooralsnog, ook geen noodzaak om een IoC component binnen te halen voor zoiets simpels. Maar ik/wij heb(ben) natuurlijk niet 't complete overzicht dat jij wél hebt en kan/kunnen dat dus moeilijk beoordelen op basis van wat we nu weten.
Defector schreef op maandag 11 september 2017 @ 12:02:
Ah volgens mij haal ik IoC en DI door elkaar.
DI is een 'subset' van IoC.

[ Voor 12% gewijzigd door RobIII op 11-09-2017 12:16 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • xFeverr
  • Registratie: Juni 2011
  • Laatst online: 10:52
Ik ben het met @RobIII eens, je zal toch ergens aan moeten geven welke implementatie voor de interface gaat gelden. Dat je het verder in de code niet uit maakt is begrijpbaar, maar ergens moet er wel een concrete klasse aan gehangen worden. Of je dat nu doet door een config-bestandje, at random of door naar de stand van de maan te kijken maakt niet uit, maar het moet wel ergens gebeuren.

Of bedoel je nu juist dat je het een lelijke oplossing vind om zo'n factory aan te roepen?

Acties:
  • 0 Henk 'm!

  • Defector
  • Registratie: December 2005
  • Niet online
Een factory lijkt mij inderdaad een goede oplossing.

Het verschil hier is dat dit even een klein projectje is. Ten opzichte van de normale projecten want daar wordt bijna standaard naar dependency injection gegrepen. Aangezien daar complexere eisen zijn.

Acties:
  • 0 Henk 'm!

  • 3raser
  • Registratie: Mei 2008
  • Laatst online: 08:20

3raser

⚜️ Premium member

Begrijp ik nu dat je een methode zoekt om te bepalen welke class (Golf, Clio, Etc.) je moet gaan inladen die allemaal het zelfde type interface (Car) gebruiken? Ben je dan niet gewoon op zoek naar Activator.CreateInstance?

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Dat is één manier (een 'implementatie' if you will) om een nieuw object te maken; je zult echter nog steeds ergens moeten bepalen of het een Golf of Clio of iets anders wordt. En dat geheel giet je in een method en stop je in een klasse en, hey presto, je hebt een factory. Of je dan new Golf() gebruikt in je factory method of Activator.CreateInstance(typeof(Golf)) is een implementatiedetail. Een factory is dus een iets hoger niveau concept dan Activator.CreateInstance.

[ Voor 5% gewijzigd door RobIII op 11-09-2017 12:33 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • 3raser
  • Registratie: Mei 2008
  • Laatst online: 08:20

3raser

⚜️ Premium member

RobIII schreef op maandag 11 september 2017 @ 12:31:
[...]

Dat is één manier (een 'implementatie' if you will) om een nieuw object te maken; je zult echter nog steeds ergens moeten bepalen of het een Golf of Clio of iets anders wordt. En dat geheel giet je in een method en stop je in een klasse en, hey presto, je hebt een factory. Of je dan new Golf() gebruikt in je factory method of Activator.CreateInstance(typeof(Golf)) is een implementatiedetail. Een factory is dus een iets hoger niveau concept dan Activator.CreateInstance.
Maar het bepalen of het een Golf of Clio wordt ligt toch gewoon aan de onderliggende data? Ik neem aan dat er ergens is opgeslagen om welke type voertuig het gaat, of dat er ergens een type voertuig wordt geselecteerd. Als je dat type weet dan is de naam voldoende om een nieuwe Instance aan te maken. Dan gaat New Golf() niet werken omdat je dan de juiste class moet gaan bepalen aan de hand van If's. Met CreateInstance kun je dynamisch de juiste class oproepen.

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
3raser schreef op maandag 11 september 2017 @ 13:22:
Maar het bepalen of het een Golf of Clio wordt ligt toch gewoon aan de onderliggende data?
Het komt "ergens" vandaan, ja, dat neem ik aan / zijn we 't over eens. Of 't nou uit een UI komt of bepaald wordt a.d.h.v. de stand van de maan of whatever maakt niet uit.
3raser schreef op maandag 11 september 2017 @ 13:22:
Als je dat type weet dan is de naam voldoende om een nieuwe Instance aan te maken. Dan gaat New Golf() niet werken omdat je dan de juiste class moet gaan bepalen aan de hand van If's. Met CreateInstance kun je dynamisch de juiste class oproepen.
Gegeven de volgende "basis":
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    interface ICar
    {
        void Drive();
        void Stop();
    }

    public abstract class Car : ICar
    {
        public void Drive() { /* ... */ }
        public void Stop() { /* ... */ }
    }
    public class Golf : Car { }
    public class Clio : Car { }
    public class Leon : Car { }


Wat is het verschil volgens jou dan tussen volgende twee implementaties?

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    class CarFactory {

        public ICar CreateCar(string name)
        {
            switch (name)
            {
                case "golf":
                    return new Golf();
                case "clio":
                    return new Clio();
                case "leon":
                    return new Leon();
                default:
                    throw new NotSupportedException();
            }
        }
    }


C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    class CarFactory {

        public ICar CreateCar(string name)
        {
            switch (name)
            {
                case "golf":
                    return (ICar)Activator.CreateInstance(typeof(Golf));
                case "clio":
                    return (ICar)Activator.CreateInstance(typeof(Clio));
                case "leon":
                    return (ICar)Activator.CreateInstance(typeof(Leon));
                default:
                    throw new NotSupportedException();
            }
        }
    }


Activator.CreateInstance heeft heus z'n nut wel, maar 't is, in deze discussie, niet meer dan een implementatiedetail betreffende hoe je de instance maakt.

Als je doelt op iets als (uit de losse pols):

C#:
1
2
3
4
5
6
7
8
    class CarFactory {

        public ICar CreateCar(string name)
        {
            var fqn = string.Format("{0}.{1}", typeof(ICar).Namespace, name);
            return (ICar)Activator.CreateInstance(Type.GetType(fqn, true, true));
        }
    }


Ja, dat scheelt een switch / boel if's, maar maakt je factory, zonder er extra werk/aandacht aan te besteden, wel vrij vatbaar voor misbruik. In essentie doe je hier een "eval()" en "eval == evil" ;) Daarbij, leert de/mijn ervaring, zal een Golf (zo niet nu danwel later) andere argumenten in de constructor verwachten dan een Leon of Clio en dan wordt het helemaal houwtje touwtje werk met Activator.CreateInstance. In het "new ...()" scenario heb je expliciet alle ondersteunde types uitgeschreven en kun je vrij eenvoudig de specifieke constructors die per ICar-implementatie (geheid gaan) verschillen met de juiste argumenten aanroepen.

Maar nogmaals; new() vs Activator.CreateInstance is een implementatie-detail en wat je daar kiest is een kwestie van persoonlijke voorkeur. Het bovenliggende concept is een factory. En alle 3 de bovenstaande CreateCar zijn dus een factory(method).

[ Voor 18% gewijzigd door RobIII op 11-09-2017 16:02 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Hydra
  • Registratie: September 2000
  • Laatst online: 21-08 17:09
Defector schreef op maandag 11 september 2017 @ 12:23:
Het verschil hier is dat dit even een klein projectje is. Ten opzichte van de normale projecten want daar wordt bijna standaard naar dependency injection gegrepen. Aangezien daar complexere eisen zijn.
Dependency injection betekent niet dat je een framework daarvoor hoeft te gebruiken. Dependency injection is eigenlijk niks meer dan in je 'root' van je applicatie at runtime die instanties te maken en dan deze aan de consumerende classes te voeren.

Verder is wat je wil gewoon exact het factory pattern.

https://niels.nu

Pagina: 1