2010-05-27 8 views
6

Ich habe eine Methode, die eine Momentaufnahme des aktuellen Zustandes zurückkehren soll, und eine andere Methode, die diesen Zustand wieder her. keine sichtbaren Methoden oder Eigenschaften - -ohne Verletzung Typsicherheit

public class MachineModel 
{ 
    public Snapshot CurrentSnapshot { get; } 
    public void RestoreSnapshot (Snapshot saved) { /* etc */ }; 
} 

Der Staat Snapshot Klasse sollte dem Anrufer völlig undurchsichtig sein, aber seine Eigenschaften sichtbar in der MachineModel Klasse. Ich konnte dies natürlich tun, indem einziehenden, das heißt haben CurrentSnapshot Rückkehr ein object und haben RestoreSnapshot ein object Argument akzeptieren, die es wieder zu einem Snapshot wirft.

aber gezwungen Guss wie das macht mich schmutzig fühlen. Was ist das beste alternative Design, das mir erlaubt, sowohl typsicher als auch undurchsichtig zu sein?

Aktualisierung mit Lösung:

gewickelt ich über Schnittstellen zu tun, eine Kombination der akzeptierte Antwort und die Anregung auf. Die Snapshot Klasse wurde eine öffentliche abstrakte Klasse, mit einer privaten Implementierung innerhalb MachineModel gemacht:

public class MachineModel 
{ 
    public abstract class Snapshot 
    { 
     protected internal Snapshot() {} 
     abstract internal void Restore(MachineModel model); 
    } 

    private class SnapshotImpl : Snapshot 
    { 
     /* etc */ 
    } 

    public void Restore(Snapshot state) 
    { 
     state.Restore(this); 
    } 
} 

Da der Konstruktor und Methoden der Snapshotinternal sind, können Anrufer von außerhalb der Baugruppe es als völlig undurchsichtig sehen und können von ihm nicht erben . Anrufer innerhalb der Baugruppe könnten Snapshot.Restore statt MachineModel.Restore anrufen, aber das ist kein großes Problem. Darüber hinaus könnte in der Praxis nie Snapshot.Restore ohne Zugang zu MachineModel ‚s private Mitglieder implementieren, die die Menschen von dem Versuch, dies zu tun abbringen sollte.

Antwort

2

Sie könnten die Abhängigkeit umkehren und ein Kind machen Snapshot (verschachtelte Klasse) von machine. Dann hat Snapshot nur eine öffentliche (oder interne) Restore() Methode, die als Parameter eine Instanz von MachineModel verwendet. Da Snapshot als untergeordnetes Objekt von MachineModel definiert ist, kann es die privaten Felder von MachineModel anzeigen.

den Zustand wiederherzustellen, haben Sie zwei Möglichkeiten im Beispiel unten. Sie können Snapshot aufrufen.RestoreState (MachineModel) oder MachineModel.Restore (Snapshot) *.

public class MachineModel 
{ 
    public class Snapshot 
    { 
     int _mmPrivateField; 

     public Snapshot(MachineModel mm) 
     { 
      // get mm's state 
      _mmPrivateField = mm._privateField; 
     } 

     public void RestoreState(MachineModel mm) 
     { 
      // restore mm's state 
      mm._privateField = _mmPrivateField; 
     } 
    } 

    int _privateField; 

    public Snapshot CurrentSnapshot 
    { 
     get { return new Snapshot(this); } 
    } 

    public void RestoreState(Snapshot ss) 
    { 
     ss.Restore(this); 
    } 
} 

Beispiel:

MachineModel mm1 = new MachineModel(); 
    MachineModel.Snapshot ss = mm1.CurrentSnapshot; 
    MachineModel mm2 = new MachineModel(); 
    mm2.RestoreState(ss); 

* Es wäre ordentlicheres sein Snapshot.RestoreState zu haben() als internal und alle Anrufer außerhalb der Versammlung gestellt, so dass der einzige Weg, eine zu tun wiederherzustellen, ist über machine. WiederherstellenState(). Aber Sie haben auf Jons Antwort erwähnt, dass es innerhalb derselben Versammlung Anrufer geben wird, also gibt es nicht viel Sinn.

3

Kann MachineModel und Snapshot in der gleichen Baugruppe und Anrufer in einer anderen Baugruppe sein? Wenn dies der Fall ist, könnte Snapshot eine öffentliche Klasse sein, aber mit ganz internen Mitgliedern.

+0

'MachineModel' wird Anrufer sowohl innerhalb derselben Baugruppe als auch von außerhalb von Baugruppen haben. –

3

Ich konnte offensichtlich dies tun, indem Downcasting, das heißt haben CurrentSnapshot ein Objekt zurückgeben, und haben RestoreSnapshot ein Objekt Argument akzeptieren, die es wieder zu einem Snapshot wirft.

Das Problem ist, dass jemand eine Instanz eines Objekts übergeben konnte, das nicht Snapshot ist.

Wenn Sie eine SchnittstelleISnapshot einzuführen, die keine Methoden aussetzt, und nur eine Implementierung vorhanden ist, können Sie fast Typsicherheit zum Preis von einem gesenkten gewährleisten.

Ich sage fast, weil Sie nicht vollständig verhindern können, jemand eine andere Implementierung von ISnapshot erstellen und übergeben, die brechen würde. Aber ich denke, das sollte das gewünschte Informationslevel bieten.

+0

Lustig, ich habe gerade den folgenden Code geschrieben und war neugierig, wie andere es schreiben würden, also googelte ich. Ich habe genau das getan, was du gesagt hast. –

Verwandte Themen