您的位置:首页 > 教育 > 培训 > 制作图片的电脑软件_装修全包报价明细表2021_百度问答平台_百度快速收录软件

制作图片的电脑软件_装修全包报价明细表2021_百度问答平台_百度快速收录软件

2024/12/7 13:31:17 来源:https://blog.csdn.net/weixin_39397471/article/details/143749380  浏览:    关键词:制作图片的电脑软件_装修全包报价明细表2021_百度问答平台_百度快速收录软件
制作图片的电脑软件_装修全包报价明细表2021_百度问答平台_百度快速收录软件

重修设计模式-行为型-备忘录模式

Captures and externalizes an object’s internal state so that it can be restored later, all without violating encapsulation.

在不违背封装原则的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象为先前的状态。

备忘录模式(Memento Pattern)允许在不暴露对象实现细节的情况下保存和恢复对象的状态。该模式的主要目的是通过捕获和存储对象的内部状态,以便将来能够将对象恢复到这个状态。

备忘录模式包含三个主要角色:

  1. 发起者(Originator):负责创建一个备忘录,并且可以记录、恢复自身的内部状态。可以根据需要决定 Memento 保存自身的那些内部状态。

  2. 备忘录(Memento):存储 Originator 内部状态的快照,防止 Originator 以外的的对象访问 Memento。

  3. 管理者(Caretaker):负责存储备忘录,但不能检查或操作备忘录的内容。

举个例子,现在需要完成一个文本编辑器,在输入文本时,程序需要将内容追加存储在内存文本中,在输入:undo命令后,会执行撤销操作,该操作会将保存的文本内容撤销到上一次输入状态。

对于该需求,首先需要创建的是编辑器类(Editor),这是编辑器需求的承载类。

class Editor {private val text: StringBuilder = StringBuilder()fun append(input: String) {this.text.append(input)}fun getText(): String = text.toString()
}

Editor 类只对外暴露 append 和 getText 方法,用于拼接内容和获取内容,符合迪米特法则,不该暴露的内部细节就不暴露。

其次需要考虑备份和恢复问题,回到备忘录模式,Editor 其实相当于 Originator 角色,这时还需要创建 Memento 角色来存储 Originator 的内部状态快照。这里需要思考两个问题:

1.能否直接复用 Editor 类作为快照的内部状态?

//如:
class Snapshot(private var editor: Editor) {fun getEditor() = editor
}//恢复时:Editor暴露set方法,便于从快照恢复状态
class Editor {//fun setText(editor: Editor) {this.text.replace(0, this.text.length, editor.getText())}...
}

直接复用 Editor 类作为内部状态,创建快照时通过深拷贝实现,好处是 Editor 需要备份的属性不用重写一份,不过缺点也显而易见:

  • 第一,为了能用快照恢复 Editor 对象,需要在 Editor 内部定义 setText() 函数,但这个函数是公用的,可能会被其他业务使用,暴露不应该暴露的函数,违背封装原则。
  • 第二,快照本身是不可变的,但上面的快照复用了业务模型 Editor 类的定义,而 Editor 类本身有一系列修改内部状态的函数,同样违背封装原则。
  • 第三,复用 Editor 意味着无法灵活选择要备份的属性,即使通过深浅拷贝的实现来达到目的(需要备份的深拷贝,不需要备份的浅拷贝或不拷贝),也会存在数据冗余问题。

2.在哪里进行快照的生成和恢复?

快照的创建和恢复方法只能在 Originator 角色内部定义,如果在 Originator 外部,就需要暴露类的所有内部细节而使其过于脆弱;如果对外屏蔽类的内部细节又无法生成快照,所以快照的生成和恢复只能由 Originator 自身来实现。这也是备忘录模式“不暴露对象实现细节的情况下,保存和恢复对象的状态”的核心。

Caretaker 角色的定义非常简答, 这里创建 SnapshotHolder 类,并在内部通过栈结构来存储历史快照。

上面的例子使用备忘录模式实现的完整代码如下:

在这里插入图片描述

//Originator:文本编辑器
class Editor {private val text: StringBuilder = StringBuilder()fun append(input: String) {this.text.append(input)}fun getText(): String = text.toString()//--生成快照--fun createSnapshot(): Snapshot {return Snapshot(text.toString())}//--从快照恢复--fun restoreSnapshot(snapshot: Snapshot) {this.text.replace(0, this.text.length, snapshot.getText())}
}//Memento:快照
class Snapshot(private val text: String) {fun getText() = text
}//Caretaker:存储快照
class SnapshotHolder {private val snapshots: Stack<Snapshot> = Stack()fun popSnapshot(): Snapshot? {return if (snapshots.isEmpty()) null else snapshots.pop()}fun pushSnapshot(snapshot: Snapshot) {snapshots.push(snapshot)}
}fun main() {println("please input:")val editor = Editor()val snapshotHolder = SnapshotHolder()val scanner = Scanner(System.`in`)while (scanner.hasNext()) {val input: String = scanner.next()if (input == ":undo") {snapshotHolder.popSnapshot()?.let { snapshot ->editor.restoreSnapshot(snapshot)  //从快照恢复上一状态} ?: println("无存储的快照了!")} else {//在发起者内部状态发生变化之前,创建快照对象,将内部状态保存。snapshotHolder.pushSnapshot(editor.createSnapshot())editor.append(input)}println("current content:${editor.getText()}")}
}

代码执行结果:

在这里插入图片描述

如何优化内存和时间消耗?

对于大对象的备份来说,备份占用的存储空间会比较大,备份和恢复的耗时会比较长。针对这个问题,不同的业务场景有不同的处理方式。比如,只备份必要的恢复信息,结合最新的数据来恢复;再比如,全量备份和增量备份相结合,低频全量备份,高频增量备份,两者结合来做恢复,具体思路如下:

当需要恢复到某一时间点的备份的时候,如果这一时间点有做全量备份,直接拿来恢复即可。如果这一时间点没有对应的全量备份,就先找到最近的一次全量备份,然后用它来恢复,之后执行此次全量备份跟这一时间点之间的所有增量备份,也就是对应的操作或者数据变动。这样就能减少全量备份的数量和频率,减少对时间、内存的消耗。

总结

备忘录模式通过封装对象的内部状态,提供了一种灵活且安全的状态管理机制,非常适合用于需要保存和恢复状态的复杂系统中,比如在需要实现撤销操作或保存和恢复对象状态的场景,例如文本编辑器、游戏状态保存等。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com