Avatar billede chrisrj Forsker
08. januar 2014 - 22:32 Der er 20 kommentarer og
1 løsning

Design spørgsmål: En røvfuld enums og switch-case, eller...?

Hejsa

Som i mit tidligere spg. (http://www.eksperten.dk/spm/989961#reply_8108703)
Sidder jeg og laver mig en lille bysamfundssimulator, og er kommet lidt i tvivl om, hvad der giver mest mening/er mest overskueligt og vedligeholdbart.

Denne gang mht. Enums.

Jeg har f.eks. disse Enums:

    public enum YesNo
    {
        Yes,
        No,
        Unknown
    }

    public enum BasicMaterialType : int
    {
        Stone,
        Wood,
        Organic,
        Metal
    }

    public enum StoneType : int
    {
        Granite=0,
        Flint
    }

    public enum WoodType : int
    {
        Oak = 0,
        Pine
    }



Og så har jeg lavet en lille klasse til at "slå op" om en given enum må bruges til en given opgave:



    // this class defines allowed and disallowed options for ressource related enums
    public static class RessourceEnum
    {

    public static YesNo IsProcessedRessource(BasicMaterialType materialtype)
        {
            switch (materialtype) {
                case BasicMaterialType.Metal:
                    return YesNo.No;
                case BasicMaterialType.Organic:
                    return YesNo.No;
                case BasicMaterialType.Stone:
                    return YesNo.No;
                case BasicMaterialType.Wood:
                    return YesNo.No;
                default:
                    return YesNo.Unknown;

            }
        }

        public static YesNo IsRawRessource(BasicMaterialType materialtype)
        {
            switch (materialtype) {
                case BasicMaterialType.Metal:
                    return YesNo.Yes;
                case BasicMaterialType.Organic:
                    return YesNo.Yes;
                case BasicMaterialType.Stone:
                    return YesNo.Yes;
                case BasicMaterialType.Wood:
                    return YesNo.Yes;
                default:
                    return YesNo.Unknown;

            }
        }
    }

Men det giver jo en frygtelig masse kode, og overblikket forsvinder hurtigt. Så hvad gør en klog? :)
Avatar billede arne_v Ekspert
08. januar 2014 - 22:39 #1
Laver en abstrakt Material klasse med abstrakte IsProcessedRessource og IsRawRessource metoder og konkrete MetalMaterial, WoodMaterial klasser.
Avatar billede arne_v Ekspert
08. januar 2014 - 22:39 #2
enum YesNo som bool eller bool? hvor du saa bruger null for unknown.
Avatar billede arne_v Ekspert
08. januar 2014 - 22:40 #3
En af de mere specielle definitioner af OOP er "switch fri programmering". Og det er kun 50% en joke.
Avatar billede chrisrj Forsker
08. januar 2014 - 23:06 #4
Hmm...umiddelbart kan jeg ikke se, at det giver mindre kode.

Men så synes du,at det giver et bedre overblik, eller hur?

Jeg har sådan set allerede en Materiale klasse, som giver egenskaberne - Enums er "bare" til navnene...så jeg kan vel (igen!)"bare" ligge disse funktioner der ind i?
Avatar billede chrisrj Forsker
08. januar 2014 - 23:08 #5
Og joh, jeg kan da godt spare den ene enum væk, det er rigtigt. ;)
Avatar billede chrisrj Forsker
09. januar 2014 - 01:13 #6
Hmmm...jeg frygter, at det her(sammen med det tidligere spg.) betyder jeg ender med noget der ligner 1000+ klasser... :s

Der MÅ være en smartere løsning.

Det er jo lige før, at jeg burde skrive en klassegenerator! :D
Avatar billede arne_v Ekspert
09. januar 2014 - 01:51 #7
Hvis du skal have rigtigt mange materialer, saa skal du maaske bare have en enkelt klasse med en property for den her info og saa en raekke per materiale?
Avatar billede chrisrj Forsker
09. januar 2014 - 09:10 #8
Hmm...hvad mener du med "række"?
Avatar billede arne_v Ekspert
09. januar 2014 - 14:57 #9
instanser af klassen

(som jeg formoder skal laeses op fra database - med en raekke per instants)
Avatar billede chrisrj Forsker
09. januar 2014 - 15:44 #10
Æhm, nej. Ikke i første omgang.

Jeg starter med at lave et lille udsnit af systemet, inden jeg går amok og laver db og jeg ska' gi' dig. ;)
Avatar billede arne_v Ekspert
10. januar 2014 - 04:11 #11
Det afgoerende er faktisk ikke hvor mange linier der skal skrives men hvor svaert det er at glemme at tilfoeje noget naar der tilfoejes et nyt materiale.

Med dit oprindelige design skal du tilfoeje til materiale enum og tilfoeje en label til et antal switche. Og du faar ingen compiler fejl hvis du glemmer noget.

De alternative metoder holder alt samlet et sted (i en type) og du kan ikke glemme noget - f.eks. giver manglende abstrakte metode i en ikke abstrakt klasse en compile fejl.
Avatar billede arne_v Ekspert
10. januar 2014 - 04:33 #12

using System;
using System.Collections.Generic;

namespace E
{
    public abstract class Material
    {
        public abstract bool? IsRawMaterial { get; }
        public bool? IsProcessed
        {
            get { return !IsRawMaterial; }
        }
        public abstract String Name { get; }
    }
    public abstract class Metal : Material
    {
        public override bool? IsRawMaterial
        {
            get { return true; }
        }
    }
    public class Iron : Metal
    {
        public override string Name
        {
            get { return "Iron"; }
        }
   
    }
    public class Copper : Metal
    {
        public override string Name
        {
            get { return "Copper"; }
        }
   
    }
    public class Concrete : Material
    {
        public override bool? IsRawMaterial
        {
            get { return false; }
        }
        public override string Name
        {
            get { return "Concrete"; }
        }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            List<Material> lst = new List<Material>();
            lst.Add(new Iron());
            lst.Add(new Concrete());
            foreach(Material m in lst)
            {
                Console.WriteLine("{0} : {1} {2}", m.Name, m.IsRawMaterial, m.IsProcessed);
            }
            Console.ReadKey();
        }
    }
}
Avatar billede arne_v Ekspert
10. januar 2014 - 04:34 #13

using System;
using System.Collections.Generic;

namespace E
{
    public class Material
    {
        public bool? IsRawMaterial { get; set; }
        public bool? IsProcessed
        {
            get { return !IsRawMaterial; }
        }
        public String Name { get; set; }
    }
    public class Program
    {
        public static void Main(string[] args)
        {
            List<Material> lst = new List<Material>();
            lst.Add(new Material{ Name = "Iron", IsRawMaterial = true });
            lst.Add(new Material{ Name = "Concrete", IsRawMaterial = false });
            foreach(Material m in lst)
            {
                Console.WriteLine("{0} : {1} {2}", m.Name, m.IsRawMaterial, m.IsProcessed);
            }
            Console.ReadKey();
        }
    }
}
Avatar billede chrisrj Forsker
10. januar 2014 - 09:17 #14
Ja, det kan jeg godt se.

Men øh...hvad laver det der "?" i f.eks. "public bool? IsRawMaterial { get; set; }"?

Det har jeg ikke set før...
Avatar billede arne_v Ekspert
10. januar 2014 - 16:17 #15
bool? er en forkortelse for Nullable<bool> og det er en type som kan have vaerdierne:
  true
  false
  null

Hvor null svarer til dit oprindelige unknown.

Overvej at droppe det helt!
Avatar billede chrisrj Forsker
10. januar 2014 - 17:06 #16
Aha.

Ja, det gør jeg også.

Grunden til at den er der, er at data modellen ikke er helt på plads, så når jeg tilføjer nye, ved jeg ikke nødvendigvis hvordan jeg vil behandle dem. :)

Når datamodellen er på plads, ryger den slags snask ud til højre. ;)
Avatar billede chrisrj Forsker
10. januar 2014 - 20:12 #17
Ok, lad mig se om jeg har det hele med:

Først har jeg nogle frø som plantes og gror til træer.

Disse træer fældes og bliver så til træstammer.

Disse træstammer laves til brædder, og disse brædder bruges til at bygge et hus.


Dvs.

Forester.AssignUseableItem(SomeSeed); //OakSeed tilføjet

Forester.Work(); //plant træer

WChopper.Harvest(SomeWood); //fælder træer og opretter et nyt Wood objekt: this.AssignedRawMaterial = new Wood(SomePlant.PlantSize, LifeLength.Long, Convert.ToInt32(SomePlant.Durability));

WChopper.Work(); // laver brædder og opretter et nyt WoodBoards objekt(ikke fuldt ud implmenteret endnu): this.AssignedRawMaterial.DoRefining(workamount, this.AssignedRefinedMaterial);

Builder.AssignUseableItem(WChopper.AssignedRefinedMaterial); //det nye WoodBoards overførers til byggeren så han kan bruge det

Builder.Work(); //huset bygges


Det "sjove" er så, at planter ligger et et andet namespace(Nature), og har derfor et helt anden klassetræ(høhø).

Det samme gælder også jobsne, men dog IKKE helt for personerne, da de deler base klasse(Organism) med Nature.

Lyder det rodet? :D
Avatar billede chrisrj Forsker
15. januar 2014 - 12:18 #18
Nå, der sker vidst ikke mere her...

Smider du lige et svar? :)
Avatar billede arne_v Ekspert
17. januar 2014 - 04:17 #19
Hvis du skal kunne arbejde med forskellinge maengder af samme materiale er du noedt til at have instanser.
Avatar billede arne_v Ekspert
17. januar 2014 - 04:17 #20
og et svar
Avatar billede chrisrj Forsker
17. januar 2014 - 09:48 #21
Ja, det er klart - og de har jo også forskellige kvaliteter. :)

Så jeg skal bare lave mig en liste, regner jeg med. ;)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester