Laden...

Wie handhabt man reine Datencontainer, wenn es keine "friend" Klassen gibt?

Erstellt von Seikilos vor 10 Jahren Letzter Beitrag vor 10 Jahren 1.512 Views
S
Seikilos Themenstarter:in
753 Beiträge seit 2006
vor 10 Jahren
Wie handhabt man reine Datencontainer, wenn es keine "friend" Klassen gibt?

Hallo,

bei einem Projekt habe ich ein Austauschobjekt, welches Projekt heißt und so aussieht:


    public class Project
    {
        public string Path { get; set; }
        public bool Active { get; set; }
    }

Diese Objekte generiert die Logik und gibt sie nach Außen (GUI), welche diese dann anzeigt.
Weil die GUI diese Objekte vorhält und braucht, um Operationen in der Logik zu triggern, reicht die GUI bei Anfragen, wie z.B "Logic.SetProjectActiveStatus(Project, bool)" das Projekt und einen bool rein.
Die Methode selber führt dann so etwas aus wie:


project.Active = false;
// Weitere Statewechsel, File IO, etc

Nun bin ich selber wegen der Unzulänglichkeit dieses Ansatz auf die Nase gefallen.
Da der Datencontainer mutable ist, hab ich in einem Unit Test anstatt des Umwegs über Logic.SetProjectActiveStatus Active manuell auf false gesetzt, denn SetProjectActiveStatus hatte bis dato nur Active = false.
Jetzt aber, durch mehr Logik in der Logik schlagen recht viele der Tests fehlt.

Hier fehlt mir ein bisschen das friend Konzept aus C++.

Wie wird das generell gehandhabt? Ich will keine Logik in die Datencontainer, d.h das Property Active soll nicht mehr tun (kann es auch garnicht, der Kontext fehlt).
Den Container immutable zu machen gefällt mir auch nicht, weil ich jedes mal neue Project instanzen erzeugen muss, die dann zur GUI, etc wandern. Dadurch muss ich die Datenhaltung in der GUI ändern, weil die Projekte nicht mehr vergleichbar sind. Außerdem muss ich die Projekte wegen so etwas wie einem geänderten Active Flag klonen.

Was würde man da machen? Eine INotifyPropertyChanged Schnittstelle wäre denkbar, aber ich will ja nicht, dass GUI auf den Daten etwas macht.

Life is a short

795 Beiträge seit 2006
vor 10 Jahren

Wie wäre es mit sowas (sehr verkürzte Form):

public interface IProject {
    string Path { get; }
    string Active { get; }
}

private class ConcreteProject : IProject {
    public string Path { get; set; }
    public string Active { get; set; }
}

public class Logic {
    public IProject CreateProject(string path) {
        return new ConcreteProject { Path = path; Active = false; };
    }
    public void SetProjectActiveStatus(IProject p, bool a) {
        ((ConcreteProject)p).Active = a;
    }
}

Gruß, Christian.

`There are 10 types of people in the world: Those, who think they understand the binary system Those who don't even have heard about it And those who understand "Every base is base 10"`
S
Seikilos Themenstarter:in
753 Beiträge seit 2006
vor 10 Jahren

Hallo,
ich bin bei der Lösung unschlüssig.
Der Contract hat dann nur die Getter, das ist ein Vorteil, aber alle Operationen auf der Logik erfordern dann das casten in die private Klasse.

Ist das der übliche Weg?

Life is a short

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Seikilos,

ich vermute mal, dass geschachtelte Klassen nicht in Frage kommen. Geschachtelte Klassen wären aus meiner Sicht am ehesten der Ersatz für Friends, denn Friends sollten m.E. eh nur Klassen sein, die in sehr enger Beziehung stehen, also insbesondere in der gleichen Assembly definiert sind. Dann kann man sie aber eben auch gleich schachteln.

aber alle Operationen auf der Logik erfordern dann das casten in die private Klasse.

Den Einwand verstehe ich nicht. Im GUI verwendest du die Schnittstelle; das GUI kennt die Klasse gar nicht. In der Logik verwendest du die Klasse und die Schnittstelle interessiert dich nicht. Was spricht bei dir dagegen?

herbivore

S
Seikilos Themenstarter:in
753 Beiträge seit 2006
vor 10 Jahren

Wenn es das übliche Vorgehen ist, stelle ich mich dem nicht entgegen, ich finde nur das casten in jeder einzelnen Methode der Logik etwas mühsam.

Bei der GUI stimme ich dem zu, dass ist elegant gelöst.

Life is a short

S
417 Beiträge seit 2008
vor 10 Jahren

Hallo,

reicht die internal Sichtbarkeit für dich evtl. aus?
Dann könntest du die setter internal machen und sie sind somit nur von deiner Logik Klasse setzbar, da sich diese in der gleichen Assembly befindet (ich nehme an, die GUI ist in einer separaten Assembly).

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Seikilos,

wenn du es so machst, wie ich geschrieben habe, musst du nicht casten, zumindest nicht dauernd.

herbivore

S
Seikilos Themenstarter:in
753 Beiträge seit 2006
vor 10 Jahren

Internal finde ich gut. Das könnte es sein.

Im GUI verwendest du die Schnittstelle; das GUI kennt die Klasse gar nicht. In der Logik verwendest du die Klasse und die Schnittstelle interessiert dich nicht. Was spricht bei dir dagegen?

Wenn das Interface IProject ist und die GUI übergibt immer das IProject an die Logik, so muss bei jeder Übergabe an die Logik das IProject in ein Project gecastet werden, damit Setter benutzt werden können.
Jede Logik Methode, die ein IProject bekommt, muss daher casten.

Life is a short

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Seikilos,

GUI übergibt immer das IProject an die Logik, so muss bei jeder Übergabe an die Logik das IProject in ein Project gecastet werden, damit Setter benutzt werden können.

das ist offensichtlich kein guter Weg, denn das GUI könnte auch ein Objekt jeder anderen Klasse übergeben, die IProject implementiert, und dann würde es knallen.

In so einer Konstellation dann doch lieber direkt die Klasse und kein Interface benutzen und stattdessen internal verwenden, damit die die Logik auf Projekt zugreifen kann, wenn sich diese eh in einer Assembly befinden.

herbivore

F
10.010 Beiträge seit 2004
vor 10 Jahren

Wenn man MVVM oder MVP ( Passiv View ) einsetzt, muss man sich über so etwas keine Gedanken machen, da hier das View nichts an die Logik übergibt.
Das ist auch der Grund warum man so etwas benutzen sollte.