Mẫu thiết kế cho công cụ hoàn tác


117

Tôi đang viết một công cụ mô hình hóa kết cấu cho một ứng dụng chế tạo máy dân dụng. Tôi có một lớp mô hình lớn đại diện cho toàn bộ tòa nhà, bao gồm các tập hợp các nút, phần tử đường, tải, v.v. cũng là các lớp tùy chỉnh.

Tôi đã viết mã một công cụ hoàn tác để lưu một bản sao sâu sau mỗi lần sửa đổi mô hình. Bây giờ tôi bắt đầu nghĩ nếu tôi có thể viết mã khác. Thay vì lưu các bản sao sâu, có lẽ tôi có thể lưu danh sách từng hành động của công cụ sửa đổi với một công cụ sửa đổi ngược tương ứng. Vì vậy, tôi có thể áp dụng các công cụ sửa đổi ngược cho mô hình hiện tại để hoàn tác hoặc các công cụ sửa đổi để làm lại.

Tôi có thể tưởng tượng bạn sẽ thực hiện các lệnh đơn giản thay đổi thuộc tính đối tượng như thế nào, v.v. Nhưng còn các lệnh phức tạp thì sao? Như chèn các đối tượng nút mới vào mô hình và thêm một số đối tượng dòng giữ các tham chiếu đến các nút mới.

Làm thế nào để thực hiện điều đó?


Nếu tôi thêm nhận xét "Hoàn tác thuật toán" sẽ làm cho nó để tôi có thể tìm kiếm "Thuật toán hoàn tác" và tìm thấy điều này? Đó là những gì tôi đã tìm kiếm và tôi thấy một cái gì đó bị đóng lại là một bản sao.
Peter Turner

Hay, tôi cũng muốn phát triển tính năng hoàn tác / làm lại trong ứng dụng chúng tôi đang phát triển. Chúng tôi sử dụng khung công tác QT4 và cần có nhiều hành động hoàn tác / làm lại phức tạp..Tôi tự hỏi, bạn đã sử dụng Command-Pattern thành công chưa?
Ashika Umanga Umagiliya

2
@umanga: Nó hoạt động nhưng nó không dễ dàng. Phần khó nhất là theo dõi các tài liệu tham khảo. Ví dụ, khi một đối tượng Frame bị xóa, các đối tượng con của nó: Nút, Tải tác động lên nó và nhiều nhiệm vụ người dùng khác cần được giữ lại để được đưa lại khi hoàn tác. Nhưng một số đối tượng con này được chia sẻ với các đối tượng khác và logic hoàn tác / làm lại trở nên khá phức tạp. Nếu mô hình không lớn như vậy, tôi sẽ giữ phương pháp lưu niệm; nó dễ thực hiện hơn nhiều.
Ozgur Ozcitak

đây là một vấn đề thú vị để giải quyết, hãy nghĩ về cách các repos mã nguồn làm điều đó, như svn (họ giữ sự khác biệt giữa các lần cam kết).
Alex

Câu trả lời:


88

Hầu hết các ví dụ tôi đã thấy sử dụng một biến thể của Command-Pattern cho việc này. Mỗi hành động người dùng có thể hoàn tác đều nhận được phiên bản lệnh của riêng nó với tất cả thông tin để thực hiện hành động và khôi phục nó. Sau đó, bạn có thể duy trì một danh sách tất cả các lệnh đã được thực thi và bạn có thể quay lại từng lệnh một.


4
Về cơ bản, đây là cách công cụ hoàn tác trong Cocoa, NSUndoManager, hoạt động.
sáng

33

Tôi nghĩ rằng cả vật lưu niệm và lệnh đều không thực tế khi bạn đang xử lý một mô hình có kích thước và phạm vi mà OP ngụ ý. Chúng sẽ hoạt động, nhưng sẽ còn rất nhiều việc để duy trì và kéo dài.

Đối với loại vấn đề này, tôi nghĩ bạn cần xây dựng hỗ trợ cho mô hình dữ liệu của mình để hỗ trợ các điểm kiểm tra khác biệt cho mọi đối tượng liên quan đến mô hình. Tôi đã làm điều này một lần và nó hoạt động rất trơn tru. Điều lớn nhất bạn phải làm là tránh sử dụng trực tiếp con trỏ hoặc tham chiếu trong mô hình.

Mọi tham chiếu đến đối tượng khác đều sử dụng một số định danh (như số nguyên). Bất cứ khi nào đối tượng là cần thiết, bạn tra cứu định nghĩa hiện tại của đối tượng từ một bảng. Bảng chứa danh sách được liên kết cho mỗi đối tượng có chứa tất cả các phiên bản trước đó, cùng với thông tin về điểm kiểm tra mà chúng đang hoạt động.

Thực hiện hoàn tác / làm lại rất đơn giản: Thực hiện hành động của bạn và thiết lập một điểm kiểm tra mới; khôi phục tất cả các phiên bản đối tượng về điểm kiểm tra trước đó.

Nó đòi hỏi một số kỷ luật trong mã, nhưng có nhiều lợi thế: bạn không cần các bản sao sâu vì bạn đang thực hiện lưu trữ khác biệt của trạng thái mô hình; bạn có thể phân chia dung lượng bộ nhớ bạn muốn sử dụng ( rất quan trọng đối với những thứ như mô hình CAD) theo số lần làm lại hoặc bộ nhớ được sử dụng; rất có thể mở rộng và bảo trì thấp cho các chức năng hoạt động trên mô hình vì chúng không cần phải làm bất cứ điều gì để thực hiện hoàn tác / làm lại.


1
Nếu bạn sử dụng một cơ sở dữ liệu (ví dụ sqlite) như là định dạng tập tin của bạn này có thể gần như tự động
Martin Beckett

4
Nếu bạn tăng cường điều này bằng cách theo dõi các phụ thuộc được giới thiệu bởi các thay đổi đối với mô hình, thì bạn có thể có một hệ thống cây hoàn tác (tức là nếu tôi thay đổi chiều rộng của một dầm, sau đó thực hiện một số công việc trên một thành phần riêng biệt, tôi có thể quay lại và hoàn tác dầm thay đổi mà không làm mất các thứ khác). Giao diện người dùng cho điều đó có thể hơi khó sử dụng nhưng nó sẽ mạnh hơn nhiều so với hoàn tác tuyến tính truyền thống.
Sumudu Fernando

Bạn có thể giải thích thêm về ý tưởng của id này so với con trỏ không? Chắc chắn một địa chỉ con trỏ / bộ nhớ hoạt động tốt như id?
paulm

@paulm: về cơ bản dữ liệu thực tế được lập chỉ mục bởi (id, phiên bản). Con trỏ đề cập đến một phiên bản cụ thể của một đối tượng, nhưng bạn đang tìm cách đề cập đến trạng thái hiện tại của một đối tượng, bất kể đó có thể là gì, vì vậy bạn muốn giải quyết nó bằng id chứ không phải theo (id, version). Bạn có thể cấu trúc lại nó để lưu trữ một con trỏ đến bảng (phiên bản => dữ liệu) và chỉ chọn cái mới nhất mỗi lần, nhưng điều đó có xu hướng gây hại cho địa phương khi bạn đang sử dụng dữ liệu, một chút lo ngại về sự nhầm lẫn và khiến bạn khó thực hiện một số loại truy vấn phổ biến, vì vậy nó không phải là cách nó thường được thực hiện.
Chris Morgan

17

Nếu bạn đang nói về GoF, mẫu Memento sẽ giải quyết cụ thể việc hoàn tác.


7
Không thực sự, điều này giải quyết cách tiếp cận ban đầu của anh ấy. Anh ấy đang yêu cầu một cách tiếp cận thay thế. Bước đầu tiên đang lưu trữ trạng thái đầy đủ cho mỗi bước trong khi bước sau chỉ lưu trữ "diffs".
Andrei Rînea

15

Như những người khác đã nêu, mẫu lệnh là một phương pháp rất mạnh để thực hiện Hoàn tác / Làm lại. Nhưng có một lợi thế quan trọng mà tôi muốn đề cập đến với mẫu lệnh.

Khi thực hiện hoàn tác / làm lại bằng cách sử dụng mẫu lệnh, bạn có thể tránh một lượng lớn mã trùng lặp bằng cách trừu tượng hóa (ở một mức độ) các thao tác được thực hiện trên dữ liệu và sử dụng các thao tác đó trong hệ thống hoàn tác / làm lại. Ví dụ, trong trình soạn thảo văn bản, việc cắt và dán là các lệnh bổ sung (ngoài việc quản lý khay nhớ tạm). Nói cách khác, thao tác hoàn tác cho một vết cắt là dán và thao tác hoàn tác cho một vết dán sẽ bị cắt. Điều này áp dụng cho các hoạt động đơn giản hơn nhiều như nhập và xóa văn bản.

Chìa khóa ở đây là bạn có thể sử dụng hệ thống hoàn tác / làm lại làm hệ thống lệnh chính cho trình soạn thảo của mình. Thay vì viết hệ thống như "tạo đối tượng hoàn tác, sửa đổi tài liệu" bạn có thể "tạo đối tượng hoàn tác, thực hiện thao tác làm lại trên đối tượng hoàn tác để sửa đổi tài liệu".

Bây giờ, phải thừa nhận rằng, nhiều người đang tự nghĩ "Chà, không phải là một phần quan điểm của mẫu lệnh sao?" Có, nhưng tôi đã thấy quá nhiều hệ thống lệnh có hai bộ lệnh, một bộ cho các hoạt động tức thì và một bộ khác để hoàn tác / làm lại. Tôi không nói rằng sẽ không có các lệnh cụ thể cho các hoạt động tức thì và hoàn tác / làm lại, nhưng việc giảm sự trùng lặp sẽ làm cho mã dễ bảo trì hơn.


1
Tôi chưa bao giờ nghĩ pastecut^ -1.
Lenar Hoyt

8

Bạn có thể muốn tham khảo mã Paint.NET để hoàn tác - họ có một hệ thống hoàn tác thực sự tốt. Nó có thể đơn giản hơn một chút so với những gì bạn cần, nhưng nó có thể cung cấp cho bạn một số ý tưởng và hướng dẫn.

-Adam


4
Trên thực tế, mã Paint.NET là không còn nữa, nhưng bạn có thể nhận được chia hai code.google.com/p/paint-mono
Igor Brejc

7

Đây có thể là trường hợp CSLA được áp dụng. Nó được thiết kế để cung cấp hỗ trợ hoàn tác phức tạp cho các đối tượng trong ứng dụng Windows Forms.


6

Tôi đã triển khai thành công các hệ thống hoàn tác phức tạp bằng cách sử dụng mẫu Memento - rất dễ dàng và có lợi ích là cung cấp một khung Làm lại một cách tự nhiên. Một lợi ích tinh tế hơn là các hành động tổng hợp cũng có thể được chứa trong một Hoàn tác duy nhất.

Tóm lại, bạn có hai chồng đồ vật lưu niệm. Một để Hoàn tác, một để Làm lại. Mỗi thao tác tạo ra một vật lưu niệm mới, lý tưởng là một số lệnh gọi để thay đổi trạng thái của mô hình, tài liệu (hoặc bất cứ thứ gì) của bạn. Điều này được thêm vào ngăn xếp hoàn tác. Khi bạn thực hiện một thao tác hoàn tác, ngoài việc thực hiện hành động Hoàn tác trên đối tượng Memento để thay đổi lại mô hình, bạn cũng bật đối tượng ra khỏi ngăn xếp Hoàn tác và đẩy nó ngay vào ngăn xếp Làm lại.

Phương pháp thay đổi trạng thái tài liệu của bạn được thực hiện như thế nào hoàn toàn phụ thuộc vào việc bạn thực hiện. Nếu bạn chỉ có thể thực hiện một lệnh gọi API (ví dụ: ChangeColour (r, g, b)), thì hãy đặt trước nó bằng một truy vấn để lấy và lưu trạng thái tương ứng. Nhưng mẫu này cũng sẽ hỗ trợ tạo bản sao sâu, ảnh chụp nhanh bộ nhớ, tạo tệp tạm thời, v.v. - tất cả tùy thuộc vào bạn vì nó chỉ đơn giản là triển khai phương pháp ảo.

Để thực hiện các hành động tổng hợp (ví dụ: người dùng Shift-Chọn một tải các đối tượng để thực hiện một thao tác, chẳng hạn như xóa, đổi tên, thay đổi thuộc tính), mã của bạn tạo một ngăn xếp Hoàn tác mới dưới dạng một kỷ niệm duy nhất và chuyển nó đến hoạt động thực tế cho thêm các hoạt động riêng lẻ vào. Vì vậy, các phương thức hành động của bạn không cần (a) phải lo lắng về một ngăn xếp toàn cục và (b) có thể được mã hóa giống nhau cho dù chúng được thực thi riêng lẻ hay là một phần của một hoạt động tổng hợp.

Nhiều hệ thống hoàn tác chỉ nằm trong bộ nhớ, nhưng bạn có thể duy trì ngăn xếp hoàn tác nếu muốn, tôi đoán vậy.


5

Tôi vừa đọc về mẫu lệnh trong cuốn sách phát triển nhanh nhẹn của tôi - có lẽ điều đó rất tiềm năng?

Bạn có thể có mọi lệnh triển khai giao diện lệnh (có phương thức Execute ()). Nếu bạn muốn hoàn tác, bạn có thể thêm phương thức Hoàn tác.

thêm thông tin ở đây


4

Tôi đồng ý với Mendelt Siebenga về thực tế là bạn nên sử dụng Command Pattern. Mẫu bạn đã sử dụng là Mẫu vật lưu niệm, có thể và sẽ rất lãng phí theo thời gian.

Vì bạn đang làm việc trên một ứng dụng sử dụng nhiều bộ nhớ, bạn sẽ có thể chỉ định dung lượng bộ nhớ mà công cụ hoàn tác được phép sử dụng, bao nhiêu cấp độ hoàn tác được lưu hoặc một số bộ nhớ mà chúng sẽ được duy trì. Không nên làm điều này, bạn sẽ sớm gặp phải lỗi dẫn đến máy bị hết bộ nhớ.

Tôi khuyên bạn nên kiểm tra xem có một khung công tác nào đã tạo mô hình cho việc hoàn tác trong ngôn ngữ / khung lập trình bạn chọn hay không. Thật tuyệt khi phát minh ra những thứ mới, nhưng tốt hơn là bạn nên sử dụng những thứ đã được viết sẵn, gỡ lỗi và thử nghiệm trong các tình huống thực tế. Sẽ hữu ích nếu bạn thêm những gì bạn đang viết này, vì vậy mọi người có thể giới thiệu các khuôn khổ mà họ biết.


3

Dự án Codeplex :

Đó là một khuôn khổ đơn giản để thêm chức năng Hoàn tác / Làm lại vào các ứng dụng của bạn, dựa trên mẫu thiết kế Lệnh cổ điển. Nó hỗ trợ các hành động hợp nhất, các giao dịch lồng nhau, thực hiện bị trì hoãn (thực hiện trên cam kết giao dịch cấp cao nhất) và lịch sử hoàn tác phi tuyến tính có thể có (nơi bạn có thể có nhiều lựa chọn để thực hiện lại).


2

Hầu hết các ví dụ tôi đã đọc đều làm điều đó bằng cách sử dụng lệnh hoặc mẫu lưu niệm. Nhưng bạn có thể làm điều đó mà không cần thiết kế các mẫu với cấu trúc deque đơn giản .


Bạn sẽ đặt những gì trong deque?

Trong trường hợp của tôi, tôi đặt trạng thái hiện tại của các hoạt động mà tôi muốn chức năng hoàn tác / làm lại. Bằng cách có hai deques (hoàn tác / làm lại), tôi sẽ hoàn tác trên hàng đợi hoàn tác (mục bật lên đầu tiên) và chèn nó vào hàng đợi làm lại. Nếu số lượng mục trong hàng đợi vượt quá kích thước ưa thích, tôi sẽ bật một mục ở đuôi.
Patrik Svensson

2
Những gì bạn mô tả thực sự một mẫu thiết kế :). Vấn đề với cách tiếp cận này là khi trạng thái của bạn chiếm nhiều bộ nhớ - việc giữ hàng chục phiên bản trạng thái sau đó trở nên không thực tế hoặc thậm chí là không thể.
Igor Brejc

Hoặc bạn có thể lưu trữ cặp đóng đại diện cho hoạt động bình thường và hoàn tác.
Xwtek

2

Một cách thông minh để xử lý việc hoàn tác, điều này sẽ làm cho phần mềm của bạn cũng phù hợp với sự cộng tác của nhiều người dùng, là thực hiện chuyển đổi hoạt động của cấu trúc dữ liệu.

Khái niệm này không phổ biến lắm nhưng được định nghĩa rõ ràng và hữu ích. Nếu định nghĩa có vẻ quá trừu tượng đối với bạn, thì dự án này là một ví dụ thành công về cách chuyển đổi hoạt động cho các đối tượng JSON được định nghĩa và triển khai trong Javascript



1

Chúng tôi đã sử dụng lại quá trình tải tệp và lưu mã tuần tự hóa cho “đối tượng” để có một biểu mẫu thuận tiện để lưu và khôi phục toàn bộ trạng thái của đối tượng. Chúng tôi đẩy các đối tượng được tuần tự hóa đó lên ngăn xếp hoàn tác - cùng với một số thông tin về thao tác đã được thực hiện và gợi ý về việc hoàn tác thao tác đó nếu không có đủ thông tin thu thập được từ dữ liệu được tuần tự hóa. Hoàn tác và Làm lại thường chỉ là thay thế một đối tượng này bằng một đối tượng khác (trên lý thuyết).

Đã có NHIỀU lỗi do con trỏ (C ++) đến các đối tượng chưa bao giờ được sửa khi bạn thực hiện một số trình tự hoàn tác kỳ lạ làm lại (những nơi đó không được cập nhật để hoàn tác an toàn hơn "số nhận dạng"). Lỗi trong lĩnh vực này thường ... ummm ... thú vị.

Một số thao tác có thể là trường hợp đặc biệt đối với tốc độ / sử dụng tài nguyên - như định kích thước mọi thứ, di chuyển mọi thứ xung quanh.

Đa lựa chọn cũng cung cấp một số phức tạp thú vị. May mắn thay, chúng tôi đã có một khái niệm nhóm trong mã. Kristopher Johnson nhận xét về các hạng mục phụ khá gần với những gì chúng tôi làm.


Điều này nghe có vẻ ngày càng không khả thi khi kích thước mô hình của bạn ngày càng lớn.
Warren P

Bằng cách nào? Cách tiếp cận này tiếp tục hoạt động mà không có thay đổi khi các "thứ" mới được thêm vào mỗi đối tượng. Hiệu suất có thể là một vấn đề khi hình thức tuần tự của các đối tượng phát triển về kích thước - nhưng đây không phải là vấn đề lớn. Hệ thống đã được phát triển liên tục trong hơn 20 năm và được hàng nghìn người dùng sử dụng.
Aardvark

1

Tôi đã phải làm điều này khi viết một giải cho một trò chơi câu đố nhảy chốt. Tôi đã thực hiện mỗi lần di chuyển một đối tượng Lệnh chứa đủ thông tin để có thể thực hiện hoặc hoàn tác. Trong trường hợp của tôi, điều này đơn giản như lưu trữ vị trí bắt đầu và hướng của mỗi bước di chuyển. Sau đó, tôi lưu trữ tất cả các đối tượng này trong một ngăn xếp để chương trình có thể dễ dàng hoàn tác nhiều lần di chuyển nếu cần trong khi bẻ khóa lại.


1

Bạn có thể thử triển khai sẵn mẫu Hoàn tác / Làm lại trong PostSharp. https://www.postsharp.net/model/undo-redo

Nó cho phép bạn thêm chức năng hoàn tác / làm lại vào ứng dụng của mình mà không cần tự triển khai mẫu. Nó sử dụng mẫu Recordable để theo dõi những thay đổi trong mô hình của bạn và nó hoạt động với mẫu INotifyPropertyChanged cũng được triển khai trong PostSharp.

Bạn được cung cấp các điều khiển giao diện người dùng và bạn có thể quyết định tên cũng như mức độ chi tiết của từng thao tác.


0

Tôi đã từng làm việc trên một ứng dụng trong đó tất cả các thay đổi được thực hiện bởi một lệnh đối với mô hình của ứng dụng (tức là CDocument ... chúng tôi đang sử dụng MFC) vẫn được duy trì ở cuối lệnh bằng cách cập nhật các trường trong cơ sở dữ liệu nội bộ được duy trì trong mô hình. Vì vậy, chúng tôi không phải viết mã hoàn tác / làm lại riêng biệt cho mỗi hành động. Ngăn xếp hoàn tác chỉ cần nhớ các khóa chính, tên trường và giá trị cũ mỗi khi bản ghi được thay đổi (ở cuối mỗi lệnh).


0

Phần đầu tiên của Mẫu thiết kế (GoF, 1994) có một trường hợp sử dụng để thực hiện hoàn tác / làm lại như một mẫu thiết kế.


0

Bạn có thể thực hiện ý tưởng ban đầu của mình.

Sử dụng cấu trúc dữ liệu liên tục và gắn bó với việc giữ một danh sách các tham chiếu đến trạng thái cũ xung quanh . (Nhưng điều đó chỉ thực sự hiệu quả nếu tất cả các hoạt động trong lớp trạng thái của bạn là không thay đổi và tất cả các hoạt động trên nó trả về một phiên bản mới --- nhưng phiên bản mới không cần phải là một bản sao sâu, chỉ cần thay thế bản sao của các phần đã thay đổi -on-ghi '.)


0

Tôi thấy Command pattern rất hữu ích ở đây. Thay vì triển khai một số lệnh đảo ngược, tôi đang sử dụng khôi phục với việc thực thi bị trì hoãn trên phiên bản thứ hai của API của tôi.

Cách tiếp cận này có vẻ hợp lý nếu bạn muốn nỗ lực triển khai thấp và khả năng bảo trì dễ dàng (và có thể dành thêm bộ nhớ cho phiên bản thứ 2).

Xem ví dụ ở đây: https://github.com/thilo20/Undo/


-1

Tôi không biết liệu điều này có ích gì cho bạn không, nhưng khi tôi phải làm điều gì đó tương tự trên một trong các dự án của mình, tôi đã tải xuống UndoEngine từ http://www.undomadeeasy.com - một công cụ tuyệt vời và tôi thực sự không quan tâm quá nhiều đến những gì bên dưới nắp ca-pô - nó chỉ hoạt động.


Vui lòng đăng nhận xét của bạn dưới dạng câu trả lời chỉ khi bạn tự tin cung cấp giải pháp! Nếu không thích đăng nó dưới dạng bình luận dưới câu hỏi! (nếu nó không cho phép làm như vậy ngay bây giờ! vui lòng đợi cho đến khi bạn có danh tiếng tốt)
InfantPro'Aravind '11/

-1

Theo tôi, UNDO / REDO có thể được thực hiện rộng rãi theo 2 cách. 1. Mức lệnh (được gọi là mức lệnh Hoàn tác / Làm lại) 2. Mức độ tài liệu (được gọi là Hoàn tác / Làm lại toàn cầu)

Mức độ lệnh: Như nhiều câu trả lời đã chỉ ra, điều này đạt được hiệu quả bằng cách sử dụng Memento pattern. Nếu lệnh cũng hỗ trợ ghi nhật ký hành động, thì việc thực hiện lại dễ dàng được hỗ trợ.

Giới hạn: Khi hết phạm vi của lệnh, không thể hoàn tác / làm lại, dẫn đến hoàn tác / làm lại cấp tài liệu (toàn cầu)

Tôi đoán trường hợp của bạn sẽ phù hợp với hoàn tác / làm lại toàn cầu vì nó phù hợp với một mô hình có nhiều không gian bộ nhớ. Ngoài ra, điều này cũng phù hợp để hoàn tác / làm lại có chọn lọc. Có hai loại nguyên thủy

  1. Hoàn tác / làm lại tất cả bộ nhớ
  2. Mức đối tượng Hoàn tác làm lại

Trong "Hoàn tác / Làm lại tất cả bộ nhớ", toàn bộ bộ nhớ được coi là dữ liệu được kết nối (chẳng hạn như cây, hoặc danh sách hoặc biểu đồ) và bộ nhớ được quản lý bởi ứng dụng chứ không phải Hệ điều hành. Vì vậy các toán tử new và delete nếu trong C ++ được nạp chồng để chứa các cấu trúc cụ thể hơn nhằm thực hiện hiệu quả các phép toán như a. Nếu bất kỳ nút nào được sửa đổi, b. giữ và xóa dữ liệu, v.v., Cách thức hoạt động của nó về cơ bản là sao chép toàn bộ bộ nhớ (giả sử rằng việc cấp phát bộ nhớ đã được ứng dụng tối ưu hóa và quản lý bằng các thuật toán nâng cao) và lưu trữ nó trong một ngăn xếp. Nếu bản sao của bộ nhớ được yêu cầu, cấu trúc cây sẽ được sao chép dựa trên nhu cầu có bản sao nông hay sâu. Bản sao sâu chỉ được tạo cho biến đó đã được sửa đổi. Vì mọi biến được phân bổ bằng cách sử dụng phân bổ tùy chỉnh, ứng dụng có tiếng nói cuối cùng để xóa nó nếu cần. Mọi thứ trở nên rất thú vị nếu chúng ta phải phân vùng Hoàn tác / Làm lại khi nó xảy ra đến mức chúng ta cần phải Lập trình chọn lọc Hoàn tác / Làm lại một tập hợp hoạt động. Trong trường hợp này, chỉ các biến mới đó, hoặc các biến đã xóa hoặc các biến đã sửa đổi mới được gắn cờ để Undo / Redo chỉ hoàn tác / làm lại bộ nhớ đó Mọi thứ thậm chí còn thú vị hơn nếu chúng ta cần thực hiện Undo / Redo một phần bên trong một đối tượng. Khi trường hợp này xảy ra, một ý tưởng mới hơn về "Mẫu khách truy cập" được sử dụng. Nó được gọi là "Hoàn tác / làm lại cấp độ đối tượng" hoặc các biến đã xóa hoặc các biến đã sửa đổi được gắn cờ để Undo / Redo chỉ hoàn tác / làm lại những bộ nhớ đó Mọi thứ thậm chí còn thú vị hơn nếu chúng ta cần thực hiện Undo / Redo một phần bên trong một đối tượng. Khi trường hợp này xảy ra, một ý tưởng mới hơn về "Mẫu khách truy cập" được sử dụng. Nó được gọi là "Hoàn tác / làm lại cấp độ đối tượng" hoặc các biến đã xóa hoặc các biến đã sửa đổi được gắn cờ để Undo / Redo chỉ hoàn tác / làm lại những bộ nhớ đó Mọi thứ thậm chí còn thú vị hơn nếu chúng ta cần thực hiện Undo / Redo một phần bên trong một đối tượng. Khi trường hợp này xảy ra, một ý tưởng mới hơn về "Mẫu khách truy cập" được sử dụng. Nó được gọi là "Hoàn tác / làm lại cấp độ đối tượng"

  1. Mức đối tượng Hoàn tác / Làm lại: Khi thông báo để hoàn tác / làm lại được gọi, mọi đối tượng thực hiện thao tác phát trực tuyến trong đó, trình phát trực tiếp nhận từ đối tượng dữ liệu cũ / dữ liệu mới được lập trình. Dữ liệu không bị xáo trộn sẽ không bị xáo trộn. Mọi đối tượng đều lấy một luồng làm đối số và bên trong lệnh gọi UNDo / Redo, nó truyền / hủy luồng dữ liệu của đối tượng.

Cả 1 và 2 đều có thể có các phương thức như 1. BeforeUndo () 2. AfterUndo () 3. BeforeRedo () 4. AfterRedo (). Các phương thức này phải được xuất bản trong Lệnh hoàn tác / làm lại cơ bản (không phải lệnh theo ngữ cảnh) để tất cả các đối tượng cũng thực hiện các phương thức này để có được hành động cụ thể.

Một chiến lược tốt là tạo ra sự kết hợp giữa 1 và 2. Cái hay là bản thân các phương pháp này (1 & 2) sử dụng các mẫu lệnh

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.