Bästa design för att skicka in många parametrar till Java metod

Permalänk
Medlem

Bästa design för att skicka in många parametrar till Java metod

Hej
Jag funderar på vad som är den bästa designen för att skicka in ett stort antal parametrar till en metod i Java. Varav dom flesta parametrarna redan har ett definierat standardvärde. Jag vill alltså att användaren av funktionen endast ska behöva fylla i ett fåtal av parametrarna, resten ska vara default.

Jag kan då tänka mig följande lösning. Man skapar ett objekt som är en ren databärare. Med alla parametrar som ska sättas. När man instansierar databärar klassen så sätts alla värden till default. Användaren kan sedan gå in och sätta om de parametrar (variabler i dataklassen) som man vill ändra på.

Typ så här:

public class DataHolder{ public int param1 = 10; public int param2 = 20; public String param3 = "hej"; public DataHolder(){}; } public class Test{ public Test( DataHolder inputParams){ //Use inputParams } } public stat void main(){ DataHolder params = new DataHolder(); params.param2 = 0; params.param3 = "hejdå"; Test test = new Test(params); }

Är detta ett vettigt sätt att lösa problemet på?
Jag ser en nackdel, och det är att om man har väldigt många parametrar som användaren vill ändra på, så kommer man få väldigt många rader med "params.parmx = y" typ av kod.

Visa signatur

Flest prylar när man dör vinner

Permalänk
Medlem
Skrivet av stenmark:

Hej
Jag funderar på vad som är den bästa designen för att skicka in ett stort antal parametrar till en metod i Java. Varav dom flesta parametrarna redan har ett definierat standardvärde. Jag vill alltså att användaren av funktionen endast ska behöva fylla i ett fåtal av parametrarna, resten ska vara default.

Jag kan då tänka mig följande lösning. Man skapar ett objekt som är en ren databärare. Med alla parametrar som ska sättas. När man instansierar databärar klassen så sätts alla värden till default. Användaren kan sedan gå in och sätta om de parametrar (variabler i dataklassen) som man vill ändra på.

Typ så här:

public class DataHolder{ public int param1 = 10; public int param2 = 20; public String param3 = "hej"; public DataHolder(){}; } public class Test{ public Test( DataHolder inputParams){ //Use inputParams } } public stat void main(){ DataHolder params = new DataHolder(); params.param2 = 0; params.param3 = "hejdå"; Test test = new Test(params); }

Är detta ett vettigt sätt att lösa problemet på?
Jag ser en nackdel, och det är att om man har väldigt många parametrar som användaren vill ändra på, så kommer man få väldigt många rader med "params.parmx = y" typ av kod.

Det funkar så som du har gjort men jag skulle förslår att du har en konstruktör i Dataholder som tar emot alla parameter som behöver initieras. På så sätt slippa du problemet som du har redan upptäckt, att man får många param.paramx =y.

public class DataHolder{ public int param1 = 0; public int param2 = 0; public String param3 = " "; public DataHolder(int param1, int param2, string param3) { this.param1 = param1; this.param2 = param2; this.param3 = param3; } }

Visa signatur

Kan din dator göra det här?

Permalänk
Medlem

Ett problem är att alla input parametrar är optional.
Om man då har 10 parametrar så behöver man väldigt många konstruktorer för att täcka alla permutationer -> ohållbart.

Jag kommer från Python där är ju problemet löst med att man i metod anropet kan ange vilka parametrar man vill använda av de som är optional. Men det finns väl inget motsvarande i Java?
Så det borde ju finnas ett Java design mönster för att lösa det problemet?

Visa signatur

Flest prylar när man dör vinner

Permalänk
Medlem
Skrivet av stenmark:

Ett problem är att alla input parametrar är optional.
Om man då har 10 parametrar så behöver man väldigt många konstruktorer för att täcka alla permutationer -> ohållbart.

Jag kommer från Python där är ju problemet löst med att man i metod anropet kan ange vilka parametrar man vill använda av de som är optional. Men det finns väl inget motsvarande i Java?
Så det borde ju finnas ett Java design mönster för att lösa det problemet?

Java mönster design är den jag visade dig.
Annars kan du skapa en struct som innehålla de parameter som du vill använda att hämta data från användare å sedan använda struct objektet i data bearbetnings klassen.

Visa signatur

Kan din dator göra det här?

Permalänk
Medlem
Skrivet av stenmark:

Jag ser en nackdel, och det är att om man har väldigt många parametrar som användaren vill ändra på, så kommer man få väldigt många rader med "params.parmx = y" typ av kod.

Inte säker på om det är bättre, men vill du undvika att behöva ett statement per parameter som ska sättas går det att lösa som:

public class DataHolder{ public int param1 = 10; public int param2 = 20; public String param3 = "hej"; public DataHolder setParam1(int param1) { this.param1 = param1; return this; } public DataHolder setParam2(int param2) { this.param2 = param2; return this; } public DataHolder setParam3(String param3) { this.param3 = param3; return this; } } public stat void main(){ DataHolder params = new DataHolder() .setParam2(0) .setParam3("hejdå"); Test test = new Test(params); }

Visa signatur

Vill du ha svar? Citera mig gärna.

Permalänk
Skrivet av stenmark:

Ett problem är att alla input parametrar är optional.
Om man då har 10 parametrar så behöver man väldigt många konstruktorer för att täcka alla permutationer -> ohållbart.

Jag kommer från Python där är ju problemet löst med att man i metod anropet kan ange vilka parametrar man vill använda av de som är optional. Men det finns väl inget motsvarande i Java?
Så det borde ju finnas ett Java design mönster för att lösa det problemet?

Om du använder en HashMap<String, Object> så kan du slänga in vilken data du vill i HashMap'en och sen i metoden ta ut det du vill ha.

HashMap<String, Object> args = new HashMap<String, Object>(); args.put("param1", 10); //args.put("param2", 20); args.put("param3", "hej"); foo(args); void foo(HashMap<String, Object> args) { Integer param1 = (Integer)args.get("param1"); System.out.println("param1 is " + param1 == null ? "missing" : param1.toString()); System.out.println("param2 is " + !args.containsKey("param2") ? "missing" : ((Integer)args.get("param2")).toString()); }

Haken är att du tappar statisk typkontroll, men det är möjligt att det vägs upp av att koden blir mer lätthanterad.

I C# har de infört Named and Optional Arguments (http://msdn.microsoft.com/en-us/library/dd264739.aspx) som gör att man kan ange bara de argument man vill och de övriga sätts till standardvärden som sätts i metod-definitionen:

void foo(string arg1, int arg2 = 5, int arg3 = 100, string arg4 = "default") { // ... } foo("string1", arg3: 42);

Generellt skulle jag säga att om en funktion tar väldigt många argument så är det en code smell (http://en.wikipedia.org/wiki/Code_smell) och antyder att det antagligen är nått större problem i koden som borde refaktoreras.

Permalänk
Medlem

Bygg en builder!

public class test { private final String namn; private final int langd; private final int kalorier; private final int proteiner; private final int kilo; private final int fett; public static class Builder { //Paramterar som krävs private String namn; private int langd; //Valfria parametrar private int kalorier = 0; private int proteiner = 0; private int kilo = 0; private int fett = 0; public Builder(String namn, int langd) { this.namn = namn; this.langd = langd; } public Builder kalorier(int val) { kalorier = val; return this; } public Builder proteiner(int val) { proteiner = val; return this; } public Builder kilo(int val) { this.kilo = val; return this; } public Builder fett(int val) { this.fett = val; return this; } public test build(){ return new test(this); } } private test(Builder builder){ namn = builder.namn; langd = builder.langd; kalorier = builder.kalorier; proteiner = builder.kalorier; kilo = builder.kilo; fett = builder.fett; } }

På så sätt slipper hålla koll på alla inparametrar vilka som är vilka o.s.v och det blir enklare att se vad du skapar..

Ett exempel när du skapar upp klassen blir alltså;

test testklass = new test.Builder("Ett Namn", 180).fett(14).kalorier(80).proteiner(3).build(); eller test test2 = new test.Builder("Namn", 175).kalorier(60).proteiner(15).build();

De obligatoriska värdena, två i detta fall, skickar du in i konstruktorn till Buildern sedan kan du chaina de valfria värdena hur som helst
Blir kanske lite mer kod, men det blir rätt mycket lättare att se vad det är för värden man skickar in

Visa signatur

WS: Mac Studio M1 Max | 32 GB | 1TB | Mac OS
WS: Intel i5 12600K | 64 GB DDR4 @3600 Mhz | 2x1TB nvme 2x1TB SSD SATA | Windows 11 & Manjaro Linux
Bärbar: Macbook Pro 14" | M1 Pro | 16GB RAM | 512GB SSD | Mac OS
Servrar: Intel i7 10700K | 64 GB DDR4 @3600Mhz | 3 TB SSD + 22TB HDD | Unraid |
4x Raspberry pi 4b 8Gb | Dietpi |