Sekvenser og indkapsling

by Jesper april 08, 2009 08:56

Jeg sidder og laver review på noget kode jeg startede på for over et år siden. Pludselig synes jeg at der er flere steder, hvor koden har fået en dårlig lugt – den virker ikke hel optimal. Jeg vil med denne post , og måske flere, forsøge at forbedre eksisterende kode. Input er selvfølgelig meget velkommen.

Det jeg netop er faldet over, og som jeg synes lugter lidt af gammel klædeskab, er følgende:

protected virtual void SetCurrent(StepBase step)
{
    if (_current != step) // Kun hvis der er tale om nyt step
    {
        try
        {
            if (_current != null)
                _current.Cleanup(); // Ryd op i nuværende Step

            step.Initialize(); // Initialicer kommende Step
            _current = step; // Sæt property-storen til nyt Step
        }
        catch (Exception ex)
        {
            _current = new ErrorStep(ex);
            OnStepError(EventArgs.Empty);
        }
        OnStepChange(EventArgs.Empty); // Fortæl omverdnen at sekvensen har ny tilstand
    }
}

Ovenstående metode, er en del af en klasse, der håndterer en sekvens. Sekvensen kan altid kun være på eet Step, og diverse transaktioner styrer sekvensen rundt mellem de mulige Step’s. Metoden er oprettet, fordi jeg mener at koden er lige en tand for kompleks, til at være i en almindelig set-accessor på en property.

Den del, jeg måske har det lidt dårligt med, er: _current.Cleanup() og _current.Initialize(). Disse to metoder bruges på de enkelte Step’s til henholdsvis at gøre klar når sekvensen indtræder i Steppet og rydde op når Steppet forlades.

Min dårlige fornemmelse går på at Sequenceklassen har ansvar for at Stepklassen initialiceres og ryddes op – det virker ikke som god stil, da man er som minimum nød til at markerer metoderne som internal, for at undgå at klientkode får adgang til dem – kun en Sequence skal have den mulighed, når nu ikke Step kan selv.

Stepklasserne kan være yderst komplekse, og have adgang til web-services og andre latente komponenter – derfor vil det ikke være en løsning at klare sagerne i konstruktør og Finalizemetoder – det vil give for dårlig performance.

Lugter denne konstruktion, og er der en smartere måde?

Tags:

Code Smell

Kommentarer

08-04-2009 14:28:43 #

Jakob Andersen

Du skriver at det er en sekvens, en sekvens er karakteriseret ved at du kan gå frem (og evt. tilbage) hvorfor har du en SetCurrent metode fremfor bare en Next() (og evt. Previous()) ?

Jakob Andersen Denmark

08-04-2009 14:41:31 #

Jesper

Jacob> Det kunne for så vidt godt være next() der bliver kaldt, men på eet eller andet tidspunkt, skal _current sættes, og samme problematik vil være gældende: Hvordan signalerer man til det gamle Step at det skal rydde op (kalde Cleanup()), og hvordan signalerer man til det nye step at der skal initialiceres (kalde Initialize())?
Ovenstående kode virker jo, men det virker som om at sekvensen har ansvar for step, og det er jo ikke nødvendigvis godt.

Jesper Denmark

09-04-2009 00:46:41 #

Mark S. Rasmussen

Current steppet, eller starting steppet kunne med fordel sendes ind i klassen i constructoren. Herefter kan der kaldes Next & Previous, og de kan med fordel smide en exception hvis ikke det er muligt, givet det nuværende step.

I både Next() og Previous() metoderne kan der fint være et if(current! = null) current.Cleanup() check (evt. med locking hvis det skal være thread safe). Ligeledes kunne både Next() og Previous() kalde Initialize på det næste step, før det sættes som current.

Mark S. Rasmussen Denmark

10-04-2009 18:16:10 #

Janus Knudsen

Det som jeg lige hæfter mig ved er at du kalder en member variable fra en protected virtual - du lægger op til at metoden kan overskrives, og overrider skal så have et kendskab den member - forvirrende vil jeg mene Smile

Jeg kan også se en sammenblanding af responsibility, altså noget i current og så noget i StepBase, nu ved jeg ikke lige, men er StepBase en baseclass til noget andet? Kunne man/ burde man måske ikke hellere holde det totalt indkapslet? Svært lige at se sammenhængen uden klassen Smile
Umiddelbart er det jo lidt antipatternsk non-OOP at smide en klasse ind i en metode på den måde der.

Janus Knudsen Denmark

12-04-2009 23:02:29 #

Jesper

Janus> Du har fat i noget af det rigtige: sammenblanding af ansvar (responsibility). Sekvensen skal ikke have ansvar for at kalde Initialize() og Cleanup() på StepBase - Den kan have ansvar for at ændre _current til et andet objekt.
Ganske rigtigt, så lægger jeg op til at sub-klasser skal kunne lave egne implementeringer af SetCurrent() - hvilket er forvirrende, og ikke giver mening.
Jeg kan derfor forestille mig en metode på StepBase, der ser således ud:
public StepBase Change(StepBase target)
{
  this.Cleanup();
  target.Initialize();
  return target;
}

Den fremgangsmåde, vil flytte ansvaret for init og cleanup hen hvor det høre til.

Jesper Denmark

15-04-2009 12:50:16 #

trackback

Sekvenser og Steps

Sekvenser og Steps

ICoder

21-04-2009 21:46:07 #

kampanye damai pemilu 2009

i want to read it but i can't speak danish.
do you know how to learn danish fast?

kampanye damai pemilu 2009 Indonesia

Kommentarerne er lukkede

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen | Modified by Mooglegiant

About

Mit navn er Jesper Jensen, og jeg arbejder til dagligt som web-udvikler hos DGI, hvor mit speciale er klientside applikationer. Før det var jeg nogle år i robotbranchen, hvor jeg arbejdede med 3D simulering og system koordinering. Jeg elsker webudvikling, og specielt JavaScript har min interesse. Jeg har blogget om mine oplevelser med udvikling siden 2004

Calendar

<<  september 2010  >>
mationtofr
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

View posts in large calendar

RecentComments

Comment RSS