Java实现23种设计模式教程(3)
动态代理(JDK动态代理)
要实现如上的结果,我们这次不用静态代理,而是用JDK动态代理
其实所谓的动态代理,也就是不用写代理类了,而是又JDK底层通过反射在内存中帮你创建好了一个代理类
public class logger implements loggers {
/**
* JDK动态代理:
* 我们无需创建代理类,而是有JDK底层的反射帮我们在内存中自动创建
*/
@Override
public void writerlogger() {
System.out.println("写入日志。。");
}
}
public interface loggers {
void writerlogger();
}
动态代理:
public class loggerProxyMain {
private static logger logger=new logger();
public static void main(String[] args) {
/**
* public static Object newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
*/
loggers loggers= (com.design.proxy.dongtaiProxy.loggers) Proxy.newProxyInstance(logger.class.getClassLoader(), logger.class.getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
第一个参数:被代理的类的对象
第二个参数:方法参数args
*/
System.out.println("代理开始====");
//如果用代理实例调用方法,将会在这里执行
Object invoke = method.invoke(logger, args);//不返回这个对象的话,代理实例为null
System.out.println("代理结束");
return invoke; //返回代理实例,并返回到loggers对象中
}
});
//****注意:进入invoke方法是有前提的,就是我们要使用代理实例对象loggers,如果不使用它就不会进入到invoke方法中
//输入logger对象也行,也可以让他进入invoke方法
// System.out.println(loggers);
/*
当我们去调用代理的方法时,method.invoke就会监听到,并执行被代理的方法
*/
loggers.writerlogger();
}
}
装饰器模式
我们可以把装饰器分为主菜和配菜,配菜就是装饰器,而主菜就是被装饰的
公式:创建一个抽象类(作为被装饰者的父类),被装饰者类去继承它,然后创建装饰者抽象类并继承被装饰者的父类,再有装饰者子类去继承装饰者抽象类。
案例:
被装饰者的抽象类,在这里是最高的类
public abstract class breakFast {
public abstract int cost(); //价格
}
被装饰者具体类
public class rice extends breakFast {
/**
* 主食:米饭
*/
@Override
public int cost() {
return 5;
}
}
public class noodles extends breakFast {
/**
*主食: 面条
*/
@Override
public int cost() {
return 10;
}
}
装饰者抽象类:继承与被装饰者的父类
public abstract class decorations extends breakFast{
public abstract int cost(); //装饰者的钱
}
装饰者类
public class coke extends decorations {
private breakFast breakFast;
private final int COKE_COST=2; //coke的价格
public coke(breakFast breakFast){
this.breakFast=breakFast;
}
@Override
public int cost() {
return breakFast.cost()+COKE_COST;
}
}
public class milk extends decorations {
private breakFast breakFast;
private final int MILK_COST=3; //milk的价格
public milk(breakFast breakFast){
this.breakFast=breakFast;
}
@Override
public int cost() {
return breakFast.cost()+MILK_COST;
}
}
测试:
public class main {
public static void main(String[] args) {
rice rice = new rice(); //创建被装饰者对象
milk milk = new milk(rice);//把被装饰者对象放到装饰者的构造方法上去
System.out.println("rice:"+rice.cost());
System.out.println("milk+rice:"+milk.cost());
milk milk1 = new milk(milk);
System.out.println("milk*2+rice"+milk1.cost());
}
}
适配器模式
适配器模式:就是把原本互不兼容的两样东西或者格式,转换成可以兼容
比如说:家用电压是220v,但是我们手机充电不需要这么大的电压,我们这时候需要电源适配器(充电头),去适配这个电压,把220v适配成(比如:5v,11v等等)
再比如说:有一个方法只能接收int类型数据,但是我们接收到了一个String类型数据,int和String本身就是两个不相同的类型,所以说这个方法是接收不到String类型的,我们可以使用适配器,把String类型转换(适配)成int类型,这样这个方法就可以接收到这个String类型数据了。
类适配器
公式:适配器类要继承src(原来的类),并实现dest(目标)接口
首先创建适配器类,并运用上面的公式:
public class classAdapter extends srcClass implements destInterface{
/**
* 类适配器是有公式的
* 公式:类适配器要继承源类,实现于目标接口
* public class classAdapter extends srcClass implements destInterface
*
* srcClass:在这里是指家用电压220V
* destInterface : 在这里是指我们想适配成多少v的电压,比如手机常用的电压 5v
*/
@Override
public int vivoBattery_5V() {
int src = super.getSrc();
int dest=src/44;
return dest;
}
}
源(src)类:
public class srcClass {
private final int v=220; //家用电压
//源类生成220v
public int getSrc(){
return v;
}
}
目标接口:
public interface destInterface {
int vivoBattery_5V(); //vivo手机想要多少伏的电压
}
测试:
public class Test {
public static void main(String[] args) {
classAdapter classAdapter = new classAdapter();
int res = classAdapter.vivoBattery_5V();
System.out.println("当前电压:"+res+"v");
}
}
对象适配器
为什么会有对象适配器:我们的对象适配器都是在类适配器上优化的,类适配器的缺点是extends(继承),因为Java是单继承的,而我们的对象适配器不过就是把这个extends srcClass 优化成一个对象,通过构造器进行传入,然后通过这个对象进行调用srcClass的方法,而类适配器就是通过super关键字去调用方法。。
public class adapter implements destInterface {
private srcClass srcClass; //把之前的类适配器的extends 源类,改成一个对象进行调用
public adapter(srcClass srcClass){ //再通过构造器传入srcClass对象
this.srcClass=srcClass;
}
@Override
public int get10V() {
int src = srcClass.getV();
int dest=src/22;
return dest;
}
}
public interface destInterface {
int get10V();
}
public class srcClass {
private final int v=220;
public int getV(){
return v;
}
}
public class Test {
public static void main(String[] args) {
adapter adapter = new adapter(new srcClass());
int v = adapter.get10V();
System.out.println(v);
}
}
接口适配器
为何有接口适配器:我们上面说的两种适配器方式都有一个缺点:就是我们上面两种适配器都需要实现目标接口,当目标接口有多个适配方法时,我们都要对它进行实现,而我们不需要全部实现,只需要实现其中一个即可,我们的接口适配器就是为了解决这个问题的。
没有给接口方法默认实现时:
public interface dest {
int adapter_5v();
int adapter_10v();
int adapter_20v();
}
public class adapter implements dest {
@Override
public int adapter_5v() {
return 0;
}
@Override
public int adapter_10v() {
return 0;
}
@Override
public int adapter_20v() {
return 0;
}
}
就需要全部进行实现,很复杂
public class srcClass {
private final int v=220; //家用电压
//源类生成220v
public int getSrc(){
return v;
}
}
public interface dest {
/**
* 当接口适配的方法很多,但是我们不需要全部的进行实现,我们可以随便给他一个默认值,用default修饰
* 当我们需要具体实现某个方法时,只需要重写对应的方法即可
*/
default int adapter_5v(){
return 0;
}
default int adapter_10v(){
return 0;
}
default int adapter_20v(){
return 0;
}
}
public class adapter implements dest {
private srcClass srcClass;
public adapter(srcClass srcClass){
this.srcClass=srcClass;
}
@Override
public int adapter_10v() {
int src = srcClass.getSrc();
int res=src/22;
return res;
}
}
class main{
public static void main(String[] args) {
adapter adapter = new adapter(new srcClass());
int i = adapter.adapter_10v();
System.out.println(i);
}
}
享元模式
享元模式:“享”是共享 ,“元”是对象 ,享元模式也就是一种利用共享技术对实例对象进行共享,提高实例对象的复用性,和节省资源的开销,减少对象的创建,应用在大量的“”相似“”对象,但是这些对象只有一些不同,我们可以用这个模式。
享元模式如何在定制相似的对象(对对象的数据进行修改):我们可以通过享元模式的简单工厂从HashMap/HashTable中get到,然后再用set方法对它进行定制。
何为相似的对象: 说白了也就是同一个类创建出来的对象就是相似的对象
案例:用户的网站界面属性(网站类型(type)、颜色(color),动态消息(message))
public abstract class website {
/**
* 总的网站抽象类
*/
public abstract void setColor(String color);
public abstract void setMessages(List<String> messages);
public abstract void setRandomCode(String randomCode);
}
public class sina extends website {
/**
* 新浪网站
*/
private final String type="新浪";
private String color;
private List<String> messages;
private String randomCode; //随机码
public sina() {
}
public String getType() {
return type;
}
public String getColor() {
return color;
}
public List<String> getMessages() {
return messages;
}
public String getRandomCode() {
return randomCode;
}
@Override
public String toString() {
return "sina{" +
"type='" + type + '\'' +
", color='" + color + '\'' +
", messages=" + messages +
", randomCode='" + randomCode + '\'' +
'}';
}
@Override
public void setColor(String color) {
this.color=color;
}
@Override
public void setMessages(List<String> messages) {
this.messages=messages;
}
@Override
public void setRandomCode(String randomCode) {
this.randomCode=randomCode;
}
}
public class zhihu extends website {
/**
* 知乎
*/
private final String type="知乎";
private String color;
private List<String> messages;
private String randomCode;
public zhihu() {
}
public String getType() {
return type;
}
public String getColor() {
return color;
}
public List<String> getMessages() {
return messages;
}
public String getRandomCode() {
return randomCode;
}
@Override
public String toString() {
return "zhihu{" +
"type='" + type + '\'' +
", color='" + color + '\'' +
", messages=" + messages +
", randomCode='" + randomCode + '\'' +
'}';
}
@Override
public void setColor(String color) {
this.color=color;
}
@Override
public void setMessages(List<String> messages) {
this.messages=messages;
}
@Override
public void setRandomCode(String randomCode) {
this.randomCode=randomCode;
}
}
享元工厂(相当于简单工厂的升级版):
这边存在线程安全问题,因为getWebsiteByFactory方法不是原子操作,所以我们多线程环境下一定要加锁
public class simpleFactory {
/**
* 享元模式是需要简单工厂模式的
*/
private Map<String,website> map=new HashMap<>(); //享元模式精髓
private String[] colors={"red","blue","yellow","green","orange"};
public website getWebsiteByFactory(String type){
if(type==null||type.equals("")) {
return null;
}else {
website website = map.get(type);
if(website==null){
//用简单工厂模式来书写
if(type.equals("新浪")){
sina sina = new sina();
Random random = new Random();
int index = random.nextInt(5);
sina.setColor(colors[index]);
int i = random.nextInt(1000);
ArrayList<String> list = new ArrayList<>();
list.add("hello"+i);
sina.setMessages(list);
sina.setRandomCode(String.valueOf(random.nextInt(9999)));
map.put(type,sina);
System.out.println("创建新浪网站对象成功");
return sina;
}else if(type.equals("知乎")){
zhihu zhihu = new zhihu();
Random random = new Random();
zhihu.setColor(colors[random.nextInt(5)]);
ArrayList<String> list = new ArrayList<>();
list.add("hello"+random.nextInt(1000));
zhihu.setMessages(list);
zhihu.setRandomCode(String.valueOf(random.nextInt(9999)));
map.put(type,zhihu);
System.out.println("创建知乎网站成功");
return zhihu;
}else {
return null;
}
}else {
System.out.println("在享元模式的简单工厂中已经存在这个网站,所以直接获取到,没有重新创建对象");
return website;
}
}
}
}
测试:
public class main {
private static final String[] websites={"新浪","知乎"};
public static void main(String[] args) {
simpleFactory simpleFactory = new simpleFactory(); //创建享元模式的简单工厂
website s1 = simpleFactory.getWebsiteByFactory("新浪");
System.out.println(s1); //会创建对象
/**
* 享元模式重要作用之一:定制对象
*/
s1.setColor("利用享元模式定制对象");
website s2 = simpleFactory.getWebsiteByFactory("新浪");
System.out.println(s2); //不会创建对象,而是从map里面拿
Random random = new Random();
// for (int i = 0; i < 20; i++) {
// new Thread(()->{
// website website = simpleFactory.getWebsiteByFactory(websites[random.nextInt(2)]);
// System.out.println(website);
//
// }).start();
// }
}
}
输出结果:
创建新浪网站对象成功
sina{type='新浪', color='red', messages=[hello713], randomCode='2522'}
在享元模式的简单工厂中已经存在这个网站,所以直接获取到,没有重新创建对象
sina{type='新浪', color='利用享元模式定制对象', messages=[hello713], randomCode='2522'}
多线程环境下的问题
只需在getWebsiteByFactory方法上加锁即可
public class simpleFactory {
/**
* 享元模式是需要简单工厂模式的
*/
private Map<String,website> map=new HashMap<>(); //享元模式精髓
private String[] colors={"red","blue","yellow","green","orange"};
public synchronized website getWebsiteByFactory(String type){
组合模式(树型结构)
组合模式的项目应用:实现多级菜单 、文件夹的管理
组合模式我们把它看成一种“树”型结构,固然后面我们在打印这些内容的时候是需要用递归的
因为组合模式是按照树形结构来组合的,所以也有树的特点(比如:叶子节点)
案例:利用组合模式来实现三级菜单。
定义组合模式的菜单组件接口,并定义添加、删除、展示结点方法:
public interface component {
/**
* 组件接口:所有菜单都要实现这个component(组件)接口
* 组合模式所需方法:添加结点、删除结点、打印菜单
*/
//需要给这个添加结点一个默认实现,因为我们的叶子结点不需要添加结点和删除结点这两个方法
default void addNode(component component){
throw new UnsupportedOperationException();//默认抛出不支持操作异常
}
default void deleteNode(component component){
throw new UnsupportedOperationException();
}
//打印===都需要实现
void showMenu();
}
菜单组件实现类(非叶子结点==第一、二级菜单):
一级菜单:
public class firstMenu implements component {
/**
* 一级菜单
*/
private String name; //菜单名称
private List<component> components;
public firstMenu(String name){
this.name=name;
this.components=new ArrayList<>();
}
@Override
public void addNode(component component) {
components.add(component);
}
@Override
public void deleteNode(component component) {
components.remove(component);
}
@Override
public void showMenu() {
System.out.println("---"+this.getName()); //打印当前调用者的名称
if(components.size()>0){
for (component component : components) {
component.showMenu(); //递归的调用这个showMenu方法
}
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<component> getComponents() {
return components;
}
public void setComponents(List<component> components) {
this.components = components;
}
}
二级菜单:
public class secondMenu implements component {
/**
* 二级菜单
*/
private String name;
private List<component> components;
public secondMenu(String name){
this.name=name;
this.components=new ArrayList<>();
}
@Override
public void addNode(component component) {
components.add(component);
}
@Override
public void deleteNode(component component) {
components.remove(component);
}
@Override
public void showMenu() {
System.out.println("------"+this.getName());
if(components.size()>0){
for (component component : components) {
component.showMenu();;
}
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<component> getComponents() {
return components;
}
public void setComponents(List<component> components) {
this.components = components;
}
}
三级菜单:(叶子节点),没有添加、删除结点方法
public class lastMenu implements component {
private String name;
/**
* 最后一个菜单(三级菜单):不能添加和删除,因为它是树的叶子结点
*/
public lastMenu(String name){
this.name=name;
}
@Override
public void showMenu() {
System.out.println("---------"+this.name);
}
}
组合模式客户端代码:
public class client {
/**
* 组合模式客户端
* @param args
*/
public static void main(String[] args) {
//创建一级菜单
component f1=new firstMenu("用户列表");
//创建二级菜单
component s1=new secondMenu("用户信息");
component s2=new secondMenu("用户权限");
component s3=new secondMenu("用户好友");
//创建三级菜单
component l1=new lastMenu("信息修改");
component l2=new lastMenu("信息删除");
component l3=new lastMenu("修改权限");
component l4=new lastMenu("添加好友");
component l5=new lastMenu("删除好友");
component l6=new lastMenu("修改好友信息");
//进行组合
f1.addNode(s1);
f1.addNode(s2);
f1.addNode(s3);
s1.addNode(l1);
s1.addNode(l2);
s2.addNode(l3);
s3.addNode(l4);
s3.addNode(l5);
s3.addNode(l6);
//展示菜单
f1.showMenu();
}
}
输出结果:
---用户列表
------用户信息
---------信息修改
---------信息删除
------用户权限
---------修改权限
------用户好友
---------添加好友
---------删除好友
---------修改好友信息
外观模式
为什么会有外观模式?外观模式能解决什么?其实就是把其他对象调用方法封装到外观类上,我们只需要通过调用外观类的方法就可以调用其他类的方法
总结:外观模式(门面模式)说白了就是把多个不同对象(类)的方法归纳到一个门面类(外观类)中,这样省去频繁创建对象,核心就是门面类
使用两种方法实现案例“买水果问题”。。
传统方式(买水果问题):
苹果实体类:
public class apple {
/**
* 苹果实体类
*/
private String id;
private String name;
public apple(String name){
this.name=name;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "apple{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
public class banana {
/**
* 香蕉实体类
*/
private String id;
private String name;
public banana(String name){
this.name=name;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "banana{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
public class orange {
/**
* 橙子实体类
*/
private String id;
private String name;
public orange(String name){
this.name=name;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "orange{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
创建各自的商店:
public class appleStore {
/**
* 苹果专卖店
*/
//买苹果
public apple buyApple(){
apple apple = new apple("苹果");
apple.setId(UUID.randomUUID().toString().replaceAll("-",""));
return apple;
}
}
public class bananaStore {
//香蕉实体店
public banana buyBanana(){
banana banana = new banana("香蕉");
banana.setId(UUID.randomUUID().toString().replaceAll("-",""));
return banana;
}
}
public class orangeStore {
//橙子实体店
public orange buyOrange(){
orange orange=new orange("橙子");
orange.setId(UUID.randomUUID().toString().replaceAll("-",""));
return orange;
}
}
顾客买水果:
public class client {
public static void main(String[] args) {
//买苹果
//1.创建苹果店对象
appleStore appleStore = new appleStore();
//2.购买
apple apple = appleStore.buyApple();
//买香蕉
bananaStore bananaStore = new bananaStore();
banana banana = bananaStore.buyBanana();
//买橙子
orangeStore orangeStore = new orangeStore();
orange orange = orangeStore.buyOrange();
System.out.println(apple);
System.out.println(banana);
System.out.println(orange);
}
}
====================
总结:可以看出来使用传统方法买水果比较复杂,顾客需要创建各自的商店,再去购买。。。
外观模式(买水果问题):
上面实体类不变,只需要添加一个门面类(外观类)即可
核心(外观类):
public class myFacade {
/**
* 创建门面类(外观类)
*/
//这几个变量也可以写成单例,这里暂且不写
private appleStore appleStore;
private bananaStore bananaStore;
private orangeStore orangeStore;
public myFacade(){
//初始化对象
this.appleStore=new appleStore();
this.bananaStore=new bananaStore();
this.orangeStore=new orangeStore();
}
/**
* 精髓。。。
* 使用外观模式的外观类来归纳方法,把多个类的方法归纳到一个外观类中
* @return
*/
//创建门面方法(外观方法),购买水果
//买苹果
public apple buyAppleByfacade(){
apple apple = appleStore.buyApple();
apple.setId(UUID.randomUUID().toString().replaceAll("-",""));
return apple;
}
//买香蕉
public banana buyBananaByfacade(){
banana banana = bananaStore.buyBanana();
banana.setId(UUID.randomUUID().toString().replaceAll("-",""));
return banana;
}
//买橙子
public orange buyOrangeByfacade(){
orange orange = orangeStore.buyOrange();
orange.setId(UUID.randomUUID().toString().replaceAll("-",""));
return orange;
}
}
public class client {
public static void main(String[] args) {
//创建已经归纳好方法的外观类
myFacade myFacade = new myFacade();
//购买水果
apple apple = myFacade.buyAppleByfacade();
banana banana = myFacade.buyBananaByfacade();
orange orange = myFacade.buyOrangeByfacade();
System.out.println(apple);
System.out.println(banana);
System.out.println(orange);
}
}
这时候我们不需要创建商店了,只需要创建外观类调用买水果方法即可。
外观模式优点:假如水果有1000种,那么我们就要创建1000个对象,而使用外观模式,只需要创建一个外观类的对象即可,只需要1个对象。这样对比起来就相当明显了。。。。。。。。。。。。。。。。。。
桥接模式
使用桥接类和需要被桥接的接口进行桥接
案例:假设我们需要一个接口,用来连接mysql或者Oracle
public interface connection {
public void connectDatasource();
}
public class connection_mysql implements connection {
/*
连接mysql数据源
*/
@Override
public void connectDatasource() {
System.out.println("mysql数据源连接成功!!!");
}
}
public class connection_oracle implements connection {
/*
连接Oracle数据源
*/
@Override
public void connectDatasource() {
System.out.println("oracle数据源连接成功!!!");
}
}
传统方式测试:
public class client_chuantong {
public static void main(String[] args) {
//传统方法调用接口方法
connection connection=new connection_mysql();
connection.connectDatasource();
connection connection1=new connection_oracle();
connection.connectDatasource();
}
}
桥的抽象类:
public abstract class bridge {
/**
* 桥的抽象类
*/
public abstract void connection();
}
桥的实现类
public class bridgeImpl extends bridge {
/**
* 核心
* 使用了桥接模式之后,我们只需要创建桥接
*/
private connection connection;
//给对象注入
public bridgeImpl(connection connection){
this.connection=connection;
}
//桥接方法(桥接接口方法)
@Override
public void connection() {
connection.connectDatasource();
}
}
桥接测试:
public class client_bridge {
public static void main(String[] args) {
//使用桥接实现类调用被桥接的接口方法
bridge bridge = new bridgeImpl(new connection_oracle());
bridge.connection();
}
}
观察者模式
既然有观察者,那么也就有被观察者。一个被观察者被多个观察者观察。比如说天气预报,天气预报就是被观察者,订阅了天气预报的人就是观察者,天气预报需要通知观察者。
被观察者接口:
public interface observerable {
/**
* 被观察者
*/
//添加观察者
public void addObserver(observer observer);
//移除观察者
public void removeObserver(observer observer);
//通知所有观察者
public void notifyAllObserver();
}
观察者接口:
public interface observer {
/**
* 观察者
*/
//接收通知的方法
public void getTianqi(tianqi tianqi);
}
被观察者(在这是天气预报):
public class tianqi implements observerable {
/**
* 被观察者 :天气预报
*/
private String date;//日期
private String wendu;//摄氏度
private List<observer> observers; //管理所有观察者,以便通知观察者们(其实也就是调用观察者的接收通知方法)
public tianqi(){
this.observers=new ArrayList<>();
this.date="2021/5/9";
this.wendu="37°C";
}
public tianqi(String date, String wendu) {
this.date=date;
this.wendu=wendu;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getWendu() {
return wendu;
}
public void setWendu(String wendu) {
this.wendu = wendu;
}
@Override
public void addObserver(observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(observer observer) {
observers.remove(observer);
}
@Override
public void notifyAllObserver() {
if(observers.size()>0){
for (int i = 0; i < observers.size(); i++) {
observers.get(i).getTianqi(new tianqi(this.date,this.wendu));
}
}else{
System.out.println("没有人订阅过天气预报。。。");
}
}
@Override
public String toString() {
return "天气信息{" +
"date='" + date + '\'' +
", wendu='" + wendu + '\'' +
'}';
}
}
观察者:
public class person implements observer {
/**
* 人:观察者
*/
private String name; //观察者名字
public person(String name){
this.name=name;
}
@Override
public void getTianqi(tianqi tianqi) {
System.out.println("当前用户名为:"+name+","+tianqi);
}
}
客户端(测试):
public class client {
public static void main(String[] args) {
tianqi tianqi = new tianqi();
tianqi.addObserver(new person("小明"));
tianqi.addObserver(new person("小华"));
tianqi.notifyAllObserver();
System.out.println("=======修改后");
tianqi.addObserver(new person("小刘"));
tianqi.setDate("2021/5/10");
tianqi.setWendu("15°C");
tianqi.notifyAllObserver();
}
}
备忘录模式
备忘录模式:可以用来备份数据和恢复
备忘录需要有三个类:需要备份的类、originator(生成需要备份的类的对象),存储数据和恢复数据的类
责任链模式
策略模式
模板模式
- 点赞
- 收藏
- 关注作者
评论(0)