【设计模式】23种设计模式——原型模式Prototype(原理讲解+应用场景介绍+案例介绍+Java代码实现)

news2024/11/28 0:51:00

原型模式

介绍

  • 原型模式指用通过拷贝原型实例创建新的实例,新实例和原型实例的属性完全一致
  • 原型模式是一种创建型设计模式
  • 工作原理是通过调用原型实例的 clone()方法来完成克隆,原型实例需要实现Cloneable接口,并重写clone()方法
  • 需要为每个类开发一个克隆方法,这对全新的类来说不难,但对已有类进行改造时,需要修改其源代码,违背了ocp原则
  • 实现深拷贝的时候可能需要比较复杂的代码

应用场景

在以下情况下,我们就不能根据new 类名()来生成实例,而是克隆现有实例来生成新实例

  • 对象种类繁多,无法将它们整合到一个类中(在软件设计中,有时候我们需要创建一种类型的对象,但是该类型下有多个具体的变体,这些变体之间可能存在大量差异,无法将这些变体都封装到一个类中。这时候可以使用原型模式,将这些变体作为原型,通过对原型进行克隆来得到新的对象。这样既避免了创建过多的分类,又能够保持对象的个性化)
  • 难以通过new来创建实例(有的实例非常复杂,想要创建一个一模一样的示例非常困难)
  • 想解耦框架与生成的实例时(想要让生成实例的框架不依赖于具体的类。这时,不能指定类名来生成实例,而要事先“注册”一个“原型”实例,然后通过复制该实例来生成新的实例)

类图

在这里插入图片描述

  • Prototype : 原型类,声明一个克隆自身的接口
  • ConcretePrototype: 具体的原型类,实现克隆方法
  • Client:调用原型对象的克隆方法,让一个原型对象克隆自身来创建一个属性一样的新对象

案例分析

克隆羊问题

现在有一只羊叫做tom,其属性为姓名: tom,年龄: 1,颜色:白色,请编写程序创建和 tom 属性完全相同的10只羊。

传统实现

package com.atguigu.prototype;

public class Sheep {
    private String name;
    private int age;
    private String color;

    public Sheep(String name, int age, String color) {
        super();
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Sheep [name=" + name + ", age=" + age + ", color=" + color + "]";
    }


}
package com.atguigu.prototype;

public class Client {

   public static void main(String[] args) {
      // TODO Auto-generated method stub
      //传统的方法
      Sheep sheep = new Sheep("tom", 1, "白色");
      
      Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
      Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
      Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
      Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
      //....
      
      System.out.println(sheep);
      System.out.println(sheep2);
      System.out.println(sheep3);
      System.out.println(sheep4);
      System.out.println(sheep5);
      //...
   }

}

分析

【优点】

  • 比较好理解,简单易操作

【缺点】

  • 在创建新的对象时,需要获取原始对象的属性,如果创建的对象比较复杂时,效率较低,不够灵活(原型对象的属性修改之后,如添加一个属性,需要往构造方法中添加参数)
  • 总是需要重新初始化对象,而不能动态地获得对象运行时的状态

【改进】

  • 使用原型模式:在Java中,Obiect类是所有类的根类,Object类提供了一个clone()方法,该方法可以将一个Java对象复制一份,但是需要实现clone的Java类必须要实现一个接口Cloneable,该接口表示该类能够复制且具有复制的能力

原型模式(浅拷贝)

package com.atguigu.prototype.improve;

/**
 * 继承Cloneable
 */
public class Sheep implements Cloneable {
    private String name;
    private int age;
    private String color;
    private String address = "蒙古羊";
    /**
     * 是对象, 克隆是会如何处理
     */
    public Sheep friend;

    public Sheep(String name, int age, String color) {
        super();
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";
    }

    /**
     * 克隆该实例,使用默认的clone方法来完成
     *
     * @return
     */
    @Override
    protected Object clone() {
        Sheep sheep = null;
        try {
            sheep = (Sheep) super.clone();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return sheep;
    }

}
package com.atguigu.prototype.improve;

public class Client {

   public static void main(String[] args) {
      System.out.println("原型模式完成对象的创建");
      Sheep sheep = new Sheep("tom", 1, "白色");
      sheep.friend = new Sheep("jack", 2, "黑色");

      Sheep sheep2 = (Sheep)sheep.clone();
      Sheep sheep3 = (Sheep)sheep.clone();
      Sheep sheep4 = (Sheep)sheep.clone();
      Sheep sheep5 = (Sheep)sheep.clone();

      System.out.println("sheep2 =" + sheep2 + "sheep2.friend=" + sheep2.friend.hashCode());
      System.out.println("sheep3 =" + sheep3 + "sheep3.friend=" + sheep3.friend.hashCode());
      System.out.println("sheep4 =" + sheep4 + "sheep4.friend=" + sheep4.friend.hashCode());
      System.out.println("sheep5 =" + sheep5 + "sheep5.friend=" + sheep5.friend.hashCode());
   }

}
原型模式完成对象的创建
sheep2 =Sheep [name=tom, age=1, color=白色, address=蒙古羊]sheep2.friend=1554874502
sheep3 =Sheep [name=tom, age=1, color=白色, address=蒙古羊]sheep3.friend=1554874502
sheep4 =Sheep [name=tom, age=1, color=白色, address=蒙古羊]sheep4.friend=1554874502
sheep5 =Sheep [name=tom, age=1, color=白色, address=蒙古羊]sheep5.friend=1554874502

Process finished with exit code 0

【分析】

  • 根据输出,可以看到其他sheep的friend原型对象的friend是同一个对象(因为hashcode一样),原因:上面的代码是浅拷贝,浅拷贝并不会重新复制一个引用类型的对象出来,只是单纯将克隆对象的friend指向原型对象的friend对象,这样的坏处是,如果原型对象的friend发生了改变,克隆对象的friend也会改变,这样不能算是真正的克隆

原型模式(深拷贝)

package com.atguigu.prototype.deepclone;

import java.io.Serializable;

public class DeepCloneableTarget implements Serializable, Cloneable {

   private static final long serialVersionUID = 1L;

   private String cloneName;

   private String cloneClass;

   /**
    * 构造器
    * @param cloneName
    * @param cloneClass
    */
   public DeepCloneableTarget(String cloneName, String cloneClass) {
      this.cloneName = cloneName;
      this.cloneClass = cloneClass;
   }

   /**
    * 因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可
    * @return
    * @throws CloneNotSupportedException
    */
   @Override
   protected Object clone() throws CloneNotSupportedException {
      return super.clone();
   }
}
package com.atguigu.prototype.deepclone;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class DeepProtoType implements Serializable, Cloneable {
    /**
     * 基本数据类型
     */
    public String name;
    /**
     * 引用类型
     */
    public DeepCloneableTarget deepCloneableTarget;

    public DeepProtoType() {
        super();
    }

    /**
     * 深拷贝 - 方式 1 使用clone 方法
     *
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //这里完成对基本数据类型(属性)和String的克隆
        Object deep = super.clone();
        //对引用类型的属性,进行单独处理
        DeepProtoType deepProtoType = (DeepProtoType) deep;
        deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();

        return deepProtoType;
    }

    /**
     * 深拷贝 - 方式2 通过对象的序列化实现 (推荐)
     * @return
     */
    public Object deepClone() {

        /// 创建流对象
        // 字节输出流
        ByteArrayOutputStream bos = null;
        // 对象输出流
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            //当前这个对象以对象流的方式输出
            oos.writeObject(this);

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            DeepProtoType copyObj = (DeepProtoType) ois.readObject();

            return copyObj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                System.out.println(e2.getMessage());
            }
        }

    }

}

【客户端调用】

package com.atguigu.prototype.deepclone;

public class Client {

   public static void main(String[] args) throws Exception {
      // TODO Auto-generated method stub
      DeepProtoType p = new DeepProtoType();
      p.name = "宋江";
      p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");

      //方式1 完成深拷贝
      DeepProtoType p2 = (DeepProtoType) p.clone();
      System.out.println("p.name=" + p.name + "; p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
      System.out.println("p2.name=" + p.name + "; p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());

      //方式2 完成深拷贝
      DeepProtoType p3 = (DeepProtoType) p.deepClone();
      System.out.println("p3.name=" + p.name + "; p3.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode());

   }

}

【运行】

p.name=宋江; p.deepCloneableTarget=1554874502
p2.name=宋江; p2.deepCloneableTarget=1846274136
p3.name=宋江; p3.deepCloneableTarget=932172204

Process finished with exit code 0

【分析】
可以看到三个对象的deepCloneableTarget的hashCode不同,因此克隆成功

字符串修饰问题

在这里插入图片描述

【框架】

package framework;

import java.lang.Cloneable;

public interface Product extends Cloneable {
    /**
     * 实例使用
     * @param s
     */
    public abstract void use(String s);

    /**
     * 实例复制
     * @return
     */
    public abstract Product createClone();
}
package framework;

import java.util.*;

public class Manager {
    /**
     * 存储实例名及实例
     */
    private HashMap showcase = new HashMap();

    /**
     * 注册示例
     * @param name
     * @param proto
     */
    public void register(String name, Product proto) {
        showcase.put(name, proto);
    }

    /**
     * 根据实例名称使用实例
     * @param protoname
     * @return
     */
    public Product create(String protoname) {
        Product p = (Product) showcase.get(protoname);
        return p.createClone();
    }
}

【实现类】

import framework.*;

/**
 * use 方法的作用是将字符串用双引号括起来显示,并在字符串下面加上下划线。例如,当 ulchar 保存的字符为'~' 方法接收到的字符串为Hello时,显示结果如下
 *
 * "Hellor"
 *  ~~~~~~
 */
public class UnderlinePen implements Product {
    private char ulchar;

    public UnderlinePen(char ulchar) {
        this.ulchar = ulchar;
    }

    public void use(String s) {
        int length = s.getBytes().length;
        System.out.println("\"" + s + "\"");
        System.out.print(" ");
        for (int i = 0; i < length; i++) {
            System.out.print(ulchar);
        }
        System.out.println("");
    }

    public Product createClone() {
        Product p = null;
        try {
            p = (Product) clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}
import framework.*;

/**
 * decochar字段中保存的是像装饰方框那样的环绕着字符串的字符。use方法会使用decochar字段中保存的字符把要显示的字符串框起来。
 * 例如,当decochar 中保存的字符为'*',use方法接收到的字符串为 Hello 的时候,显示结果如下
 * <p>
 * *******
 * *Hello*
 * *******
 */
public class MessageBox implements Product {
    private char decochar;

    public MessageBox(char decochar) {
        this.decochar = decochar;
    }

    public void use(String s) {
        int length = s.getBytes().length;
        for (int i = 0; i < length + 4; i++) {
            System.out.print(decochar);
        }
        System.out.println("");
        System.out.println(decochar + " " + s + " " + decochar);
        for (int i = 0; i < length + 4; i++) {
            System.out.print(decochar);
        }
        System.out.println("");
    }

    public Product createClone() {
        Product p = null;
        try {
            p = (Product) clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

【主类】

import framework.*;

public class Main {
    public static void main(String[] args) {
        // 准备
        Manager manager = new Manager();
        UnderlinePen upen = new UnderlinePen('~');
        MessageBox mbox = new MessageBox('*');
        MessageBox sbox = new MessageBox('/');
        manager.register("strong message", upen);
        manager.register("warning box", mbox);
        manager.register("slash box", sbox);

        // 生成
        Product p1 = manager.create("strong message");
        p1.use("Hello, world.");
        System.out.println();
        Product p2 = manager.create("warning box");
        p2.use("Hello, world.");
        System.out.println();
        Product p3 = manager.create("slash box");
        p3.use("Hello, world.");
    }
}
"Hello, world."
 ~~~~~~~~~~~~~

*****************
* Hello, world. *
*****************

/
/ Hello, world. /
/

Process finished with exit code 0

分析

对象种类繁多,无法将它们整合到一个类中时

在示例程序中,一共出现了如下3种样式。

  • 使用’~'为字符串添加下划线
  • 使用’*'为字符串添加边框
  • 使用’/'为字符串添加边框

本例比较简单,只生成了3种样式,不过无论多少种样式都可以生成。但是如果将每种样式都编写为一个类,类的数量将会非常庞大,源代码的管理也会变得非常困难。

想解耦框架与生成的实例时

在示例程序中,我们将复制(clone)实例的部分封装在framework包中了

在Manager类的create方法中,我们并没有使用类名,而是根据"strong message"和"slash box"等字符串(即实例名称)来生成相应的实例。与Java语言自带的生成实例的newSomething()方式相比,这种方式具有更好的通用性,且将框架从类名的束缚中解脱出来了

登场角色

在这里插入图片描述

  • Prototype(原型):定义用于复制现有实例来生成新实例的方法,如上面的Product
  • ConcretePrototype(具体的原型):负责实现复制现有实例并生成新实例的方法,如上面的MessageBox和UnderlinePen
  • Client(使用者):负责使用复制实例的方法生成新的实例,如上面的Manager

Spring源码分析

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:p="http://www.springframework.org/schema/p"
   xmlns:util="http://www.springframework.org/schema/util"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">


 <!-- 这里我们的 scope="prototype" 即 原型模式来创建 -->
 <bean id="id01" class="com.atguigu.spring.bean.Monster" 
   scope="prototype"/>
   
</beans>

scope=“prototype”:使用原型模式

package com.atguigu.spring.bean;

/**
 * 注释
 * @author Administrator
 *
 */
public class Monster {

   private Integer id = 10 ;
   private String nickname = "牛魔王";
   private String skill = "芭蕉扇";
   public Monster() {
      
      System.out.println("monster 创建..");
   }
   public Monster(Integer id, String nickname, String skill) {
      //System.out.println("Integer id, String nickname, String skill被调用");
      this.id = id;
      this.nickname = nickname;
      this.skill = skill;
   }
   
   public Monster( String nickname, String skill,Integer id) {
      
      this.id = id;
      this.nickname = nickname;
      this.skill = skill;
   }
   public Integer getId() {
      return id;
   }
   public void setId(Integer id) {
      this.id = id;
   }
   public String getNickname() {
      return nickname;
   }
   public void setNickname(String nickname) {
      this.nickname = nickname;
   }
   public String getSkill() {
      return skill;
   }
   public void setSkill(String skill) {
      this.skill = skill;
   }
   @Override
   public String toString() {
      return "Monster [id=" + id + ", nickname=" + nickname + ", skill="
            + skill + "]";
   }
   
}
package com.atguigu.spring.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ProtoType {

   public static void main(String[] args) {
      // TODO Auto-generated method stub
      ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
      // 获取monster[通过id获取monster]
      Object bean = applicationContext.getBean("id01");
      System.out.println("bean" + bean); // 输出 "牛魔王" .....
      
      Object bean2 = applicationContext.getBean("id01");
      System.out.println("bean2" + bean2); //输出 "牛魔王" .....
      System.out.println(bean == bean2); // false,并不是同一个对象,只是属性相同

   }

}

【运行】

monster 创建..
beanMonster [id=10, nickname=牛魔王, skill=芭蕉扇]
monster 创建..
bean2Monster [id=10, nickname=牛魔王, skill=芭蕉扇]
false

Process finished with exit code 0

在这里插入图片描述

浅拷贝和深拷贝

浅拷贝

  • 对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象
  • 对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值 (内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
  • sheep = (Sheep) super.clone()这种方式就是浅拷贝

深拷贝

  • 复制对象的所有基本数据类型的成员变量值
  • 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象

【实现方式】

  • 重写clone方法来实现深拷贝(缺点:麻烦,每个子对象都需要调用克隆方法重新赋值)
  • 通过对象序列化实现深拷贝(缺点:速度慢,如果调用拷贝的次数多,不要使用这种方式)

深拷贝工具类

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;


public class DeepCloneUtil {
   
   public static Object deepClone(Object srcObject){
      ByteArrayOutputStream bos = null;
      ObjectOutputStream oos = null;
      ByteArrayInputStream bis = null;
      ObjectInputStream ois = null;
      Object result = null;
      try {
         bos = new ByteArrayOutputStream();
         oos = new ObjectOutputStream(bos);
         oos.writeObject(srcObject);
         bis = new ByteArrayInputStream(bos.toByteArray());
         ois = new ObjectInputStream(bis);
         result = ois.readObject();
      } catch (Exception e) {
         e.printStackTrace();
      } finally {
         try {
            bos.close();
            oos.close();
            bis.close();
            ois.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
      return result;
   }

}

使用方式

A a = new A();
A a1 = (A)DeepCloneUtil.deepClone(a);

clone方法与Clonable接口

  • Object中定义了clone()方法,如果类实现了Cloneable接口,就可以调用clone()来进行实例复制;否则调用就会报CloneNotSupportedException异常
  • Cloneable接口中并没有声明任何方法。它只是被用来标记“可以使用clone方法进行复制”的,称为标记接口(marker interface)
  • clone 方法只会进行复制,并不会调用被复制实例的构造函数。此外,对于在生成实例时需要进行特殊的初始化处理的类,需要自已去实现 clone 方法,在其内部进行这些初始化处理

在这里插入图片描述

文章说明

  • 本文章为本人学习尚硅谷的学习笔记,文章中大部分内容来源于尚硅谷视频(点击学习尚硅谷相关课程),也有部分内容来自于自己的思考,发布文章是想帮助其他学习的人更方便地整理自己的笔记或者直接通过文章学习相关知识,如有侵权请联系删除,最后对尚硅谷的优质课程表示感谢。
  • 本人还同步阅读《图解设计模式》书籍(图解设计模式/(日)结城浩著;杨文轩译–北京:人民邮电出版社,2017.1),进而综合两者的内容,让知识点更加全面

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/780051.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WSR-88D天气雷达工作模式、监测目标、反射率含义讲解

一、WSR-88D 简介 WSR-88D是天气监视多普勒雷达之一。自 1988 年首次建造和测试以来,它已在包括阿拉斯加和夏威夷在内的美国 160 多个地点安装和使用。WSR-88D也已安装在波多黎各和太平洋的几个岛屿。 WSR-88D雷达发射功率为750000瓦(平均灯泡只有75瓦)!这种功率使雷达产…

03. 自定义镜像 Dockerfile

目录 1、前言 2、构建镜像的方式 2.1、docker commit 2.1.1、先查看下当前的容器 2.1.2、生成该容器镜像 2.1.3、查看镜像列表 2.2、Dockerfile 2.2.1、创建Dockerfile文件 2.2.2、编写Dockerfile文件 2.2.3、构建镜像 2.2.4、使用该镜像生成容器 3、Dockerfile 3…

Docker 网络、资源控制

Docker 网络、资源控制 一、Docker 网络1、Docker 网络实现原理2、Docker 的网络模式&#xff1a;1&#xff0e;host模式2&#xff0e;container模式3&#xff0e;none模式4&#xff0e;bridge模式5&#xff0e;自定义网络 二、资源控制1&#xff0e;CPU 资源控制&#xff08;1…

用echarts绘制流程图

getEchart1() {echarts.init(document.getElementById(echart1)).dispose();var chartDom document.getElementById(echart1);this.myChart echarts.init(chartDom);var charts {nodes: [ // 节点{name: 开始, value: [0, 500],label: {borderWidth: 1, // 边框宽度borderRa…

【CMU15-445 FALL 2022】Project #1 - Buffer Pool

About 实验官网 Project #1 - Buffer Pool在线评测网站 gradescope Lab Task #1 - Extendible Hash Table 详见——【CMU15-445 FALL 2022】Project #1 - Extendable Hashing 如果链接失效&#xff0c;请查看当前平台我之前发布的文章。 Task #2 - LRU-K Replacement Polic…

flink Mysql CDC(动态加表)、postgresqlCDC 和 CDC无锁算法

flinkCDC - 功能验证记录 flink 与cdc 版本使用搭配&#xff1a;flink cdc参数说明原理分析&#xff08;DBLog&#xff09;无锁算法论文 mysql cdccdc api 动态加表flink cdc sql 性能压测flink cdc api 性能压测 PostgreSqlCDC执行更新语句&#xff0c;会出现 2 种情况 cdc si…

【数据挖掘】bytewax 与 ydata工具可实时了解您的数据

一、说明 在这篇博文中&#xff0c;我们将介绍如何将开源流式处理解决方案 bytewax 与 ydata 分析相结合并加以利用&#xff0c;以提高流式处理流的质量。 STream 处理支持在传输中和存储之前对数据进行实时分析&#xff0c;并且可以是有状态的&#xff0c;也可以是无状态的。 …

[STL]vector使用介绍

[STL]vector使用介绍 注&#xff1a;文内代码均在Visual Studio 2013下进行测试&#xff0c;不同的编译器下在扩容大小等方面可能有所不同&#xff0c;但不影响各接口函数的使用。 文章目录 [STL]vector使用介绍1. vector介绍2. 构造函数3. 迭代器相关函数begin函数和end函数的…

实现点击复制到剪切板功能

该功能使用VueUse实现 什么是 VueUse VueUse不是Vue.use&#xff0c;它是为Vue 2和3服务的一套Vue Composition API的常用工具集&#xff0c;是目前世界上Star最高的同类型库之一。它的初衷就是将一切原本并不支持响应式的JS API变得支持响应式&#xff0c;省去程序员自己写相…

jmeter常用的提取器(正则表达式和JSON提取器)

jmeter常用的后置处理器有两种提取数据&#xff1a; 1、JSON提取器 获取后可以将变量token引用到其他所需要的地方 &#xff08;正则表达式和JSON提取器&#xff09;:2023接口自动化测试框架必会两大神器:正则提取器和Jsonpath提取器_哔哩哔哩_bilibilihttps://www.bilibili.…

uniapp实战

上面是tab栏&#xff0c;下面是swiper&#xff0c;&#xff0c;tab和swiper和 红色滑块 动态变化&#xff0c;&#xff0c; 遇到的问题&#xff1a; 往下滚动 tab栏 吸顶&#xff1a; position:sticky; z-index:99; top:0;swiper切换触发 change 事件&#xff0c; :current …

SOMEIP协议--第四节[ SOME/IP](someip概述与行为)

SOMEIP协议–第四节[ SOME/IP](someip概述与行为) 文章目录 SOMEIP协议--第四节[ SOME/IP](someip概述与行为)1、概述2、someip的行为2.1 基础传输2.2 SOME/IP-TP传输:2.3 someip参数(client)2.4 someip参数(server)1、概述 Method | Event | Field是上层设计的三个概念…

【C++】优先级队列和反向迭代器 模拟笔记

文章目录 优先级队列仿函数适配器模式堆知识储备 反向迭代器代码&#xff08;反向迭代器&#xff09;代码&#xff08;优先级队列&#xff09; 优先级队列 仿函数 仿函数&#xff0c;它不是函数&#xff08;其实是个类&#xff09;&#xff0c;但用法和函数一样。既然是个类&a…

子类化QThread来实现多线程,moveToThread函数的作用

子类化QThread来实现多线程&#xff0c; QThread只有run函数是在新线程里的&#xff0c;其他所有函数都在QThread生成的线程里。正确启动线程的方法是调用QThread::start()来启动。 一、步骤 子类化 QThread&#xff1b;重写run&#xff0c;将耗时的事件放到此函数执行&#…

轻量级Web报表工具ActiveReportsJS全新发布v4.0,支持集成更多前端框架!

ActiveReportsJS 是一款基于 JavaScript 和 HTML5 的轻量级Web报表工具&#xff0c;采用拖拽式设计模式&#xff0c;不需任何服务器和组件支持&#xff0c;即可在 Mac、Linux 和 Windows 操作系统中&#xff0c;设计多种类型的报表。ActiveReportsJS 同时提供跨平台报表设计、纯…

18.背景轮播

背景轮播 html部分 <div class"container"><div class"slide active" style"background-image: url(./static/20180529205331_yhGyf.jpeg);"></div><div class"slide " style"background-image: url(./s…

vue3+taro+Nutui 开发小程序(二)

上一篇我们初始化了小程序项目&#xff0c;这一篇我们来整理一下框架 首先可以看到我的项目整理框架是这样的&#xff1a; components:这里存放封装的组件 custom-tab-bar:这里存放自己封装的自定义tabbar interface&#xff1a;这里放置了Ts的一些基本泛型&#xff0c;不用…

AtcoderABC238场

A - Exponential or QuadraticA - Exponential or Quadratic 题目大意 给定一个整数 n&#xff0c;判断是否满足 2n >n 2。 思路分析 根据数学知识可知n 的取值在 2 到 4 之间&#xff08;包括 2 和 4&#xff09;&#xff0c;不满足条件 。 时间复杂度 O(1) AC代码 …

MyBatis学习笔记——4

MyBatis学习笔记——4 一、MyBatis的高级映射及延迟加载1.1、多对一1.1.1、第一种方式&#xff1a;级联属性映射1.1.2、第二种方式&#xff1a;association1.1.3、第三种方式&#xff1a;分步查询 1.2、一对多1.2.1、第一种方式&#xff1a;collection1.2.1、第二种方式&#x…

Linux Ubuntu crontab 添加错误 提示:no crontab for root - using an empty one 888

资料 错误提示&#xff1a; no crontab for root - using an empty one 888 原因剖析&#xff1a; 第一次使用crontab -e 命令时会让我们选择编辑器&#xff0c;很多人会不小心选择默认的nano&#xff08;不好用&#xff09;&#xff0c;或则提示no crontab for root - usin…