import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** * Created by zz on 2023/11/5 */ public class Memo { private static List<Integer> offsets = new ArrayList<>(); private final static String fileName = "/Users/szhang/Project75/src/text.txt"; public static void main(String[] args) throws IOException { String contents = new BufferedReader(new FileReader(fileName)).readLine(); while (true) { try { // keep scanning input from user; String reader = new Scanner(System.in).nextLine(); // if input is (:list), then print out file content; if (":list".equals(reader)) { System.out.println(contents); } else if (":undo".equals(reader)) { int offset = offsets.get(offsets.size() - 1); offsets.remove(offsets.size() - 1); contents = contents.substring(0, contents.length() - offset); BufferedWriter writer = new BufferedWriter(new FileWriter(fileName)); writer.write(contents); } else { String newContent = reader; offsets.add(newContent.length()); contents += newContent; BufferedWriter writer = new BufferedWriter(new FileWriter(fileName)); writer.write(contents); } } catch (Exception ignored) { } // if input is (:undo), then remove last time input and print out file the latest content; // use an offset to keep tracking previous added string length; } } }
public class InputText { private StringBuilder text = new StringBuilder(); public String getText() { return text.toString(); } public void append(String input) { text.append(input); } public void setText(String text) { this.text.replace(0, this.text.length(), text); } } public class SnapshotHolder { private Stack<InputText> snapshots = new Stack<>(); public InputText popSnapshot() { return snapshots.pop(); } public void pushSnapshot(InputText inputText) { InputText deepClonedInputText = new InputText(); deepClonedInputText.setText(inputText.getText()); snapshots.push(deepClonedInputText); } } public class ApplicationMain { public static void main(String[] args) { InputText inputText = new InputText(); SnapshotHolder snapshotsHolder = new SnapshotHolder(); Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { String input = scanner.next(); if (input.equals(":list")) { System.out.println(inputText.getText()); } else if (input.equals(":undo")) { InputText snapshot = snapshotsHolder.popSnapshot(); inputText.setText(snapshot.getText()); } else { snapshotsHolder.pushSnapshot(inputText); inputText.append(input); } } } }
上面的代码的问题在于:
针对以上两点,可以:
public class InputText { private StringBuilder text = new StringBuilder(); public String getText() { return text.toString(); } public void append(String input) { text.append(input); } public Snapshot createSnapshot() { return new Snapshot(text.toString()); } public void restoreSnapshot(Snapshot snapshot) { this.text.replace(0, this.text.length(), snapshot.getText()); } } public class Snapshot { private String text; public Snapshot(String text) { this.text = text; } public String getText() { return this.text; } } public class SnapshotHolder { private Stack<Snapshot> snapshots = new Stack<>(); public Snapshot popSnapshot() { return snapshots.pop(); } public void pushSnapshot(Snapshot snapshot) { snapshots.push(snapshot); } } public class ApplicationMain { public static void main(String[] args) { InputText inputText = new InputText(); SnapshotHolder snapshotsHolder = new SnapshotHolder(); Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { String input = scanner.next(); if (input.equals(":list")) { System.out.println(inputText.toString()); } else if (input.equals(":undo")) { Snapshot snapshot = snapshotsHolder.popSnapshot(); inputText.restoreSnapshot(snapshot); } else { snapshotsHolder.pushSnapshot(inputText.createSnapshot()); inputText.append(input); } } } }
和我最开始的那个实现的区别在于:
- 不用offset,因为offset会频繁读写文件,还是基于文件的内容,而snapshot相当于新加了一个数据结构来存储每一个版本,可以当真正需要最后一步关闭的时候再去将最新的内容写进去即可。
- 不破坏封装。通过多了一层数据结构(snapshot类),将包含直接修改内容的数据操作与容器分类开来。减少风险。
不同场景需求不同策略