2012-01-24 21 views

Trả lời

15

Một tính năng hiển nhiên sẽ là generics, việc triển khai một bộ lưu trữ chung sẽ cho phép bạn sử dụng nó cho bất kỳ đối tượng nào bạn muốn.

Nhiều ví dụ mà bạn sẽ thấy sẽ sử dụng một chuỗi (bao gồm tất cả những câu trả lời cho câu hỏi này) vì đây là một vấn đề vì đây là một trong số ít loại .NET là không thay đổi.

Khi xử lý các đối tượng có thể thay đổi (như bất kỳ loại tham chiếu nào với thuộc tính setter), bạn phải nhớ rằng khi lưu lưu trữ, bạn cần tạo bản in sâu của đối tượng. Nếu không, bất cứ khi nào bạn thay đổi đối tượng ban đầu của bạn, bạn sẽ thay đổi vật lưu niệm của bạn.

Bạn có thể thực hiện việc này bằng cách sử dụng trình nối tiếp như protobuf-net hoặc json.net vì chúng không yêu cầu bạn đánh dấu đối tượng bằng thuộc tính tuần tự như cơ chế tuần tự .net bình thường.

CodeProject có vài bài viết về hiện thực vật lưu niệm chung chung, nhưng họ có xu hướng bỏ qua phần deepcopy:

Generic Memento Pattern for Undo-Redo in C#

Memento Design Pattern

+0

Bạn có thể thêm bất kỳ thông tin nào khác về phần bản sao sâu không? Một liên kết đến một ví dụ về phần này của việc thực hiện hoặc một cái gì đó. Câu trả lời tuyệt vời để cảm ơn ... – MoonKnight

+0

Chỉ cần nhìn thấy liên kết bên dưới. Cảm ơn. – MoonKnight

3

Tôi không biết bất kỳ cách nào được tích hợp sẵn để hỗ trợ mẫu Memento. Tôi thấy một vài triển khai bằng cách sử dụng .NET Mock frameworks, trong đó trong thực tế một bản sao của đối tượng được tạo ra và có thể là trường với dữ liệu, nhưng tôi xem xét nó là loại phí.

Sử dụng Memento patter khi Hoàn tác/Làm lại thường, có thể bạn cũng vậy. Trong trường hợp này, tốt hơn nên có ít dữ liệu hơn trên Hoàn tác/Làm lại ngăn xếp càng tốt, do đó, tùy chỉnh undoable object là một cái gì đó mà Tôi sẽ sử dụng.

Hy vọng điều này sẽ hữu ích.

2

Có một điều sẽ làm cho mẫu này nhanh hơn để viết trong C# và đó là bất kỳ trường trạng thái nào có thể được khai báo là public readonly vì vậy bạn không cần các thuộc tính hoặc phương thức 'get' để truy cập chúng.

Đây là chuyển đổi thẳng với public readonly bao gồm.

class Originator 
{ 
    private string state; 
    // The class could also contain additional data that is not part of the 
    // state saved in the memento. 

    public void Set(string state) 
    { 
     Console.WriteLine("Originator: Setting state to " + state); 
     this.state = state; 
    } 

    public Memento SaveToMemento() 
    { 
     Console.WriteLine("Originator: Saving to Memento."); 
     return new Memento(state); 
    } 

    public void RestoreFromMemento(Memento memento) 
    { 
     state = memento.SavedState; 
     Console.WriteLine("Originator: State after restoring from Memento: " + state); 
    } 

    public class Memento 
    { 
     public readonly string SavedState; 

     public Memento(string stateToSave) 
     { 
      SavedState = stateToSave; 
     } 
    } 
} 

class Caretaker 
{ 
    static void Main(string[] args) 
    { 
     List<Originator.Memento> savedStates = new List<Originator.Memento>(); 

     Originator originator = new Originator(); 
     originator.Set("State1"); 
     originator.Set("State2"); 
     savedStates.Add(originator.SaveToMemento()); 
     originator.Set("State3"); 
     // We can request multiple mementos, and choose which one to roll back to. 
     savedStates.Add(originator.SaveToMemento()); 
     originator.Set("State4"); 

     originator.RestoreFromMemento(savedStates[1]); 
    } 
} 
+0

Bạn có chắc chắn xây dựng tư nhân chính xác cho lớp Memento? là nó có thể truy cập từ Originator? –

+0

Bạn đã đúng! Tôi đã không biên dịch điều này hoặc một cái gì đó geez. Bây giờ cố định của nó nhờ. –

1

một sử dụng Generics tôi đã tìm thấy here:

#region Originator 
public class Originator<T> 
{ 
    #region Properties 
    public T State { get; set; } 
    #endregion 
    #region Methods 
    /// <summary> 
    /// Creates a new memento to hold the current 
    /// state 
    /// </summary> 
    /// <returns>The created memento</returns> 
    public Memento<T> SaveMemento() 
    { 
     return (new Memento<T>(State)); 
    } 
    /// <summary> 
    /// Restores the state which is saved in the given memento 
    /// </summary> 
    /// <param name="memento">The given memento</param> 
    public void RestoreMemento(Memento<T> memento) 
    { 
     State = memento.State; 
    } 
    #endregion 
} 
#endregion 
#region Memento 
public class Memento<T> 
{ 
    #region Properties 
    public T State { get; private set; } 
    #endregion 
    #region Ctor 
    /// <summary> 
    /// Construct a new memento object with the 
    /// given state 
    /// </summary> 
    /// <param name="state">The given state</param> 
    public Memento(T state) 
    { 
     State = state; 
    } 
    #endregion 
} 
#endregion 
#region Caretaker 
public class Caretaker<T> 
{ 
    #region Properties 
    public Memento<T> Memento { get; set; } 
    #endregion 
} 
#endregion 
#region Originator 
public class Originator<T> 
{ 
    #region Properties 
    public T State { get; set; } 
    #endregion 
    #region Methods 
    /// <summary> 
    /// Creates a new memento to hold the current 
    /// state 
    /// </summary> 
    /// <returns>The created memento</returns> 
    public Memento<T> SaveMemento() 
    { 
     return (new Memento<T>(State)); 
    } 
    /// <summary> 
    /// Restores the state which is saved in the given memento 
    /// </summary> 
    /// <param name="memento">The given memento</param> 
    public void RestoreMemento(Memento<T> memento) 
    { 
     State = memento.State; 
    } 
    #endregion 
} 
#endregion 
#region Memento 
public class Memento<T> 
{ 
    #region Properties 
    public T State { get; private set; } 
    #endregion 
    #region Ctor 
    /// <summary> 
    /// Construct a new memento object with the 
    /// given state 
    /// </summary> 
    /// <param name="state">The given state</param> 
    public Memento(T state) 
    { 
     State = state; 
    } 
    #endregion 
} 
#endregion 
#region Caretaker 
public class Caretaker<T> 
{ 
    #region Properties 
    public Memento<T> Memento { get; set; } 
    #endregion 
} 
#endregion 

Được sử dụng như thế này:

Originator<string> org = new Originator<string>(); 
    org.State = "Old State"; 
    // Store internal state in the caretaker object 
    Caretaker<string> caretaker = new Caretaker<string>(); 
    caretaker.Memento = org.SaveMemento(); 
    Console.WriteLine("This is the old state: {0}", org.State); 
    org.State = "New state"; 
    Console.WriteLine("This is the new state: {0}", org.State); 
    // Restore saved state from the caretaker 
    org.RestoreMemento(caretaker.Memento); 
    Console.WriteLine("Old state was restored: {0}", org.State); 
    // Wait for user 
    Console.Read(); 

Như @Simon Skov Boisen đề cập đến điều này sẽ chỉ làm việc cho dữ liệu không thay đổi và đòi hỏi một deep copy.

+2

Xem câu trả lời của tôi, bạn phải xem xét sâu hơn khi xử lý các loại tham chiếu với các thuộc tính setter. –

Các vấn đề liên quan