diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 0ac79bc01a286677afda45cfe0a92d9bd1037fd1..64112cd37b645a3948e9a462c336d1cd181e7fdd 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -19,6 +19,7 @@ + @@ -29,6 +30,7 @@ + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml index 941db19f8a0b53e36347ec48fe4c37261f145d05..c156c3c1eb69215b7aff4cb6178a22c1f5c83871 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -15,6 +15,8 @@ + + diff --git a/.idea/misc.xml b/.idea/misc.xml index f243497297db0c4b43f436d25ae1e4244fec8476..513980f7a19b944ae2709bde445ec3eacdd8e686 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -19,6 +19,7 @@ diff --git a/README.md b/README.md index bc08496b42f979af1494eaac9ad5c3eb499c3e56..51146a59bcd1bea84c8cf8322aeb06d393a42456 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,31 @@ * 需要在运行时动态决定使用哪些对象和方法的时候。 比如,对于监控系统来说,很多时候需要监控运行时的程序状态,但大多数时候又无法预知对象编译时的状态和参数,这时使用访问者模式就可以动态增加监控行为。 +# 6.8 备忘录模式 +### 6.8.1 备忘录模式介绍 + +备忘录模式提供了一种对象状态的撤销实现机制,当系统中某一个对象需要恢复到某一历史状态时可以使用备忘录模式进行设计. + + + +> 很多软件都提供了撤销(Undo)操作,如 Word、记事本、Photoshop、IDEA等软件在编辑时按 Ctrl+Z 组合键时能撤销当前操作,使文档恢复到之前的状态;还有在 浏览器 中的后退键、数据库事务管理中的回滚操作、玩游戏时的中间结果存档功能、数据库与操作系统的备份操作、棋类游戏中的悔棋功能等都属于这类。 + +**备忘录模式(memento pattern)定义: 在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态.** + +![img.png](img/img_memento_pattern_eg.png) + +### 6.8.2 备忘录模式原理 + +![img.png](img/img_memento_pattern_principle.png) + +备忘录模式的主要角色如下: + +* 发起人(Originator)角色:状态需要被记录的元对象类, 记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。 +* 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。 +* 看护人(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。 + + + 1. 使用 Readme.md 来支持不同的语言, Readme\_en.md: 支持英文, Readme\_zh.md: 支持中文 2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 小的进步,才是大的开始!!! diff --git a/byv-memento-patttern-19/.gitignore b/byv-memento-patttern-19/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5ff6309b7199129c1afe4f4ec1906e640bec48c6 --- /dev/null +++ b/byv-memento-patttern-19/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/byv-memento-patttern-19/pom.xml b/byv-memento-patttern-19/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ac12e69c0950a7cf7f209c2fbd1e1c7ec2bf2939 --- /dev/null +++ b/byv-memento-patttern-19/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + org.example + byv-memento-patttern-19 + 1.0-SNAPSHOT + + + 8 + 8 + UTF-8 + + + + + org.projectlombok + lombok + 1.18.28 + compile + + + org.dom4j + dom4j + 2.1.3 + + + jaxen + jaxen + 1.1.6 + + + log4j + log4j + 1.2.12 + + + org.slf4j + slf4j-api + 1.7.36 + + + com.alibaba + fastjson + 1.2.62 + + + junit + junit + 4.12 + compile + + + + + \ No newline at end of file diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Client.java b/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Client.java new file mode 100644 index 0000000000000000000000000000000000000000..45aa67de391f6fdf4452559943fbec6dac832527 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Client.java @@ -0,0 +1,27 @@ +package com.boyunv.memento.example01; +/* + *@description + * + *@author boyunv + *@create 2023/9/4 7:51 + *@version 1.0 + */ + +public class Client { + + public static void main(String[] args) { + + //创建人发起对象 + Originator originator = new Originator(); + originator.setId("1"); + originator + .setName("ww"); + originator.setPhone("1233333"); + System.out.println("============"+originator); + + Creataker creataker = new Creataker(); + creataker.setMemento(originator.createMemento()); + originator.setName("eeee"); + System.out.println("============"+originator); + } +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Creataker.java b/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Creataker.java new file mode 100644 index 0000000000000000000000000000000000000000..dc547dd0c89f9a9ee54e45f66fe5216f2e76f286 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Creataker.java @@ -0,0 +1,16 @@ +package com.boyunv.memento.example01; + +import lombok.Data; + +/* + *@description + * 负责人类 + *@author boyunv + *@create 2023/9/4 7:50 + *@version 1.0 + */ +@Data +public class Creataker { + + private Memento memento; +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Memento.java b/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Memento.java new file mode 100644 index 0000000000000000000000000000000000000000..598691d373413a3aaef5b91955461508edb569c4 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Memento.java @@ -0,0 +1,32 @@ +package com.boyunv.memento.example01; + +import lombok.Data; +import lombok.ToString; + +/* + *@description + * 备忘录角色 + * 访问权限:默认:在同包下不可见,只有访问者才可以访问 + *@author boyunv + *@create 2023/9/4 7:42 + *@version 1.0 + */ +@Data +@ToString + class Memento { + + private String state="从备份对象恢复原始对象 原始对象"; + + private String id; + private String name; + private String phone; + + public Memento() { + } + + public Memento(String id, String name, String phone) { + this.id = id; + this.name = name; + this.phone = phone; + } +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Originator.java b/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Originator.java new file mode 100644 index 0000000000000000000000000000000000000000..238345827c0cc55db982c703b321c6dbd8f02508 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/memento/example01/Originator.java @@ -0,0 +1,39 @@ +package com.boyunv.memento.example01; + +import lombok.Data; +import lombok.ToString; + +/* + *@description + * + *@author boyunv + *@create 2023/9/4 7:40 + *@version 1.0 + */ +@Data +@ToString +public class Originator { + public Originator() { + } + + + private String state="原始对象"; + + private String id; + private String name; + private String phone; + + //恢复对象的方法 + public Memento restoreMemento(Memento mo){ + this.state=mo.getState(); + this.id=mo.getId(); + this.name=mo.getName(); + this.phone=mo.getPhone(); + return mo; + } + + //创建备忘录对象 + public Memento createMemento(){ + return new Memento(id,name,phone); + } +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Acceptable.java b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Acceptable.java new file mode 100644 index 0000000000000000000000000000000000000000..9b04250b0c6d19d4257504f502d5ca09387f4213 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Acceptable.java @@ -0,0 +1,14 @@ +package com.boyunv.visitor.example01; +/* + *@description + * 接待者接口 (抽下昂元素接口) + *@author boyunv + *@create 2023/9/3 9:42 + *@version 1.0 + */ + +public interface Acceptable { + + //接受所有visitor访问者的子类 + public void accept(Visitor visitor); +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Candy.java b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Candy.java new file mode 100644 index 0000000000000000000000000000000000000000..b9ced9d2f9a907dfeaba614a6aa40744437f5b80 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Candy.java @@ -0,0 +1,24 @@ +package com.boyunv.visitor.example01; +/* + *@description + * 糖果类 + *@author boyunv + *@create 2023/9/3 9:21 + *@version 1.0 + */ + +import java.time.LocalDate; + +public class Candy extends Product implements Acceptable{ + public Candy(String name, LocalDate producedDate, double price) { + super(name, producedDate, price); + } + + + @Override + public void accept(Visitor visitor) { + //accept方法中调用访问者,并将this传递回去 + visitor.visit(this); + + } +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Client.java b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Client.java new file mode 100644 index 0000000000000000000000000000000000000000..e18059e62c4bd5353b6affb6973a3e9192bf7900 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Client.java @@ -0,0 +1,48 @@ +package com.boyunv.visitor.example01; +/* + *@description + * + *@author boyunv + *@create 2023/9/3 9:37 + *@version 1.0 + */ + +import java.text.NumberFormat; +import java.time.LocalDate; +import java.util.Arrays; +import java.util.List; + +public class Client { + public static void main(String[] args) { + LocalDate billDate = LocalDate.now(); + + Candy candy = new Candy("徐福记",LocalDate.of(2022,10,1),10.0); + System.out.println("糖果: " + candy.getName()); + + double rate = 0.0; + + long days = billDate.toEpochDay() - candy.getProducedDate().toEpochDay(); + System.out.println(days); + + if(days > 180){ + System.out.println("超过半年的糖果,请勿食用!"); + }else{ + rate = 0.9; + double discountPrice = candy.getPrice() * rate; + System.out.println("打折后的价格"+ NumberFormat.getCurrencyInstance().format(discountPrice)); + } + + //三件商品加入购物车 //模拟添加多个商品 + List products = Arrays.asList( + new Candy("金丝猴奶糖",LocalDate.of(2022,6,10),10.00), + new Wine("衡水老白干",LocalDate.of(2020,6,10),100.00), + new Fruit("草莓",LocalDate.of(2022,10,12),50.00,1) + ); + + Visitor visitor = new DiscountVisitor(LocalDate.of(2022,10,17)); + for (Acceptable product : products) { + product.accept(visitor); + } + + } +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/DiscountVisitor.java b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/DiscountVisitor.java new file mode 100644 index 0000000000000000000000000000000000000000..c69c7c508c91d2a314c38dc63c068a63a6964133 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/DiscountVisitor.java @@ -0,0 +1,63 @@ +package com.boyunv.visitor.example01; +/* + *@description + * 折扣计价访问者类 + *@author boyunv + *@create 2023/9/3 9:26 + *@version 1.0 + */ + +import java.text.NumberFormat; +import java.time.LocalDate; + +public class DiscountVisitor implements Visitor{ + + private LocalDate billDate; + + public DiscountVisitor(LocalDate billDate) { + this.billDate = billDate; + System.out.println("结算日期: " + billDate); + } + + @Override + public void visit(Candy candy) { + System.out.println("糖果: " + candy.getName()); + + //糖果大于180天,禁止售卖,否则九折 + long days=billDate.toEpochDay()-candy.getProducedDate().toEpochDay(); + if(days>180){ + System.out.println("超过半年的糖果,请勿食用!"); + }else{ + double rate = 0.9; + double discountPrice = candy.getPrice() * rate; + System.out.println("糖果打折后的价格"+ NumberFormat.getCurrencyInstance().format(discountPrice)); + } + + } + + @Override + public void visit(Wine wine) { + System.out.println("酒类: " + wine.getName()+",无折扣价格!"); + System.out.println("原价: "+NumberFormat.getCurrencyInstance().format(wine.getPrice())); + } + + @Override + public void visit(Fruit fruit) { + System.out.println("水果: " + fruit.getName()); + //获取产品生产天数 + long days = billDate.toEpochDay() - fruit.getProducedDate().toEpochDay(); + + double rate = 0; + + if(days > 7){ + System.out.println("超过七天的水果,请勿食用!"); + }else if(days > 3){ + rate = 0.5; + }else{ + rate = 1; + } + + double discountPrice = fruit.getPrice() * fruit.getWeight() * rate; + System.out.println("水果价格: "+NumberFormat.getCurrencyInstance().format(discountPrice)); + } +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Fruit.java b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Fruit.java new file mode 100644 index 0000000000000000000000000000000000000000..f714d45afa59f3b874aa9dc84906e72afc712d1a --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Fruit.java @@ -0,0 +1,37 @@ +package com.boyunv.visitor.example01; +/* + *@description + * + *@author boyunv + *@create 2023/9/3 9:22 + *@version 1.0 + */ + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDate; + +public class Fruit extends Product implements Acceptable{ + + @Setter + @Getter + private double weight; + + public Fruit(String name, LocalDate producedDate, double price) { + super(name, producedDate, price); + } + + public Fruit(String name, LocalDate producedDate, double price, double weight) { + super(name, producedDate, price); + this.weight = weight; + } + @Override + public void accept(Visitor visitor) { + //accept方法中调用访问者,并将this传递回去 + visitor.visit(this); + + } +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Product.java b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Product.java new file mode 100644 index 0000000000000000000000000000000000000000..45366ccc128a74653da6e98ae805514dfc9b8a4a --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Product.java @@ -0,0 +1,20 @@ +package com.boyunv.visitor.example01; +/* + *@description + * 抽象商品父类 + *@author boyunv + *@create 2023/9/3 9:19 + *@version 1.0 + */ + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.time.LocalDate; +@Data +@AllArgsConstructor +public abstract class Product { + private String name; //商品名 + private LocalDate producedDate; // 生产日期 + private double price; //单品价格 +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Visitor.java b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Visitor.java new file mode 100644 index 0000000000000000000000000000000000000000..83807c476d8d60c6a6a19a67cbbad62f8933be34 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Visitor.java @@ -0,0 +1,17 @@ +package com.boyunv.visitor.example01; +/* + *@description + * 访问者接口-根据入参不同调用对应的重载方法 + *@author boyunv + *@create 2023/9/3 9:24 + *@version 1.0 + */ + +public interface Visitor { + + public void visit(Candy candy); //糖果重载方法 + + public void visit(Wine wine); //酒类重载方法 + + public void visit(Fruit fruit); //水果重载方法 +} diff --git a/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Wine.java b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Wine.java new file mode 100644 index 0000000000000000000000000000000000000000..e6b866ddc23e064257d5c0c6c0d7982a6326b411 --- /dev/null +++ b/byv-memento-patttern-19/src/main/java/com/boyunv/visitor/example01/Wine.java @@ -0,0 +1,23 @@ +package com.boyunv.visitor.example01; +/* + *@description + *酒水类 + *@author boyunv + *@create 2023/9/3 9:21 + *@version 1.0 + */ + +import java.time.LocalDate; + +public class Wine extends Product implements Acceptable{ + public Wine(String name, LocalDate producedDate, double price) { + super(name, producedDate, price); + } + + @Override + public void accept(Visitor visitor) { + //accept方法中调用访问者,并将this传递回去 + visitor.visit(this); + + } +} diff --git a/byv-memento-patttern-19/src/main/resources/config.xml b/byv-memento-patttern-19/src/main/resources/config.xml new file mode 100644 index 0000000000000000000000000000000000000000..7cbe016568f295adf6621d9d76f83604173b20e5 --- /dev/null +++ b/byv-memento-patttern-19/src/main/resources/config.xml @@ -0,0 +1,4 @@ + + + com.boyunv.strategy.example03.MT1101HandlerStrategy + \ No newline at end of file diff --git a/img/img_memento_pattern_eg.png b/img/img_memento_pattern_eg.png new file mode 100644 index 0000000000000000000000000000000000000000..a9841df5a08d86bf8e3d280e9a010eedc241205e Binary files /dev/null and b/img/img_memento_pattern_eg.png differ diff --git a/img/img_memento_pattern_principle.png b/img/img_memento_pattern_principle.png new file mode 100644 index 0000000000000000000000000000000000000000..1751add6e7e1d694b11769d56c21b74ff8ff468e Binary files /dev/null and b/img/img_memento_pattern_principle.png differ