【Vue】Vue 前端设计模式梳理

news/2024/3/29 18:10:24/文章来源:https://blog.csdn.net/weixin_53791978/article/details/130380515

文章目录

        • 一、什么是设计模式?
        • 二、设计几个原则
        • 三、常见的设计模式及实际案例
          • 【1】单例模式
            • 1. 什么是单例模式?
            • 2.Vue中的单例模式
          • 【2】工厂模式
            • 1. 什么是工厂模式?
            • 2.Vue中的工厂模式
          • 【3】策略模式
            • 1. 什么是策略模式?
            • 2.策略模式的实际应用
          • 【4】代理模式
            • 1. 什么是代理模式?
            • 2.代理模式在实战中的应用
          • 【5】适配器模式
            • 1. 什么是适配器模式?
            • 2.适配器的实际案例
          • 【5】观察者模式/发布-订阅模式
            • 1. 什么是观察者模式?
            • 2. 什么是发布-订阅模式?
            • 3.Vue中的发布-订阅模式


一、什么是设计模式?

设计模式是一套被反复使用、多数人知晓、经过分类编目的、代码设计经验的总结。它是为了可重用代码,让代码更容易的被他人理解并保证代码的可靠性。
设计模式实际上是“拿来主义”在软件领域的贯彻实践,它是一套现成的工具,拿来即用。下面来看一下设计模式的设计原则。

二、设计几个原则

单一职责原则、开放封闭原则、里式替换原则、接口隔离原则 、依赖反转原则 、最少知识原则。

三、常见的设计模式及实际案例

单例模式、工厂模式、策略模式、代理模式、适配器模式、观察者模式/发布-订阅模式

【1】单例模式
1. 什么是单例模式?

单例模式 (Singleton Pattern)又称为单体模式,保证一个类只有一个实例,并提供一个访问它的全局访问点。也就是说,第二次使用同一个类创建新对象的时候,应该得到与第一次创建的对象完全相同的对象。

2.Vue中的单例模式

(1)Element UI

Element UI是使用Vue开发的一个前端UI框架。ElementUI 中的全屏 Loading 蒙层调用有两种形式:
●指令形式:Vue.use(Loading.directive)=>使用方式 :<div :v-loading.fullscreen="true">...</div>;
●服务形式:Vue.prototype.$loading = service=>使用方式 :this.$loading({ fullscreen: true });

用服务方式使用全屏 Loading 是单例的,即在前一个全屏 Loading 关闭前再次调用全屏 Loading,并不会创建一个新的 Loading 实例,而是返回现有全屏 Loading 的实例。下面是 ElementUI 实现全屏 Loading 的源码:

import Vue from 'vue'
import loadingVue from './loading.vue'
const LoadingConstructor = Vue.extend(loadingVue)
let fullscreenLoading
const Loading = (options = {}) => {if (options.fullscreen && fullscreenLoading) {return fullscreenLoading}let instance = new LoadingConstructor({el: document.createElement('div'),data: options})if (options.fullscreen) {fullscreenLoading = instance}return instance
}
export default Loading

这里的单例是 fullscreenLoading,是存放在闭包中的,如果用户传的 options 的 fullscreen 为 true 且已经创建了单例,则直接返回之前创建的单例,如果之前没有创建过,则创建单例并赋值给闭包中的 fullscreenLoading 后返回新创建的单例实例。

(2)Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。Vuex,它们都实现了一个全局的 Store 用于存储应用的所有状态。这个 Store 的实现,正是单例模式的典型应用。Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。——Vuex官方文档

// 安装vuex插件
Vue.use(Vuex)
// 将store注入到Vue实例中
new Vue({el: '#app',store
})

通过调用Vue.use()方法,安装了 Vuex 插件。Vuex 插件是一个对象,它在内部实现了一个 install 方法,这个方法会在插件安装时被调用,从而把 Store 注入到Vue实例里去。也就是说每 install 一次,都会尝试给 Vue 实例注入一个 Store。

let Vue // 这个Vue的作用和楼上的instance作用一样
...
export function install (_Vue) {// 判断传入的Vue实例对象是否已经被install过Vuex插件(是否有了唯一的state)if (Vue && _Vue === Vue) {if (process.env.NODE_ENV !== 'production') {console.error('[vuex] already installed. Vue.use(Vuex) should be called only once.')}return}// 若没有,则为这个Vue实例对象install一个唯一的VuexVue = _Vue// 将Vuex的初始化逻辑写进Vue的钩子函数里applyMixin(Vue)
}

可以保证一个 Vue 实例(即一个 Vue 应用)只会被 install 一次 Vuex 插件,所以每个 Vue 实例只会拥有一个全局的 Store。

【2】工厂模式
1. 什么是工厂模式?

工厂模式就是根据不用的输入返回不同的实例,一般用来创建同一类对象,它的主要思想就是将对象的创建与对象的实现分离。
在创建对象时,不暴露具体的逻辑,而是将逻辑封装在函数中,那么这个函数就可以被视为一个工厂。工厂模式根据抽象程度的不同可以分为:简单工厂、工厂方法、抽象工厂。

2.Vue中的工厂模式

(1)VNode

和原生的 document.createElement 类似,Vue 这种具有虚拟 DOM 树(Virtual Dom Tree)机制的框架在生成虚拟 DOM 的时候,提供了 createElement 方法用来生成 VNode,用来作为真实 DOM 节点的映射:

createElement('h3', { class: 'main-title' }, [createElement('img', { class: 'avatar', attrs: { src: '../avatar.jpg' } }),createElement('p', { class: 'user-desc' }, 'hello world')
])

createElement 函数结构大概如下:

class Vnode (tag, data, children) { ... }
function createElement(tag, data, children) {return new Vnode(tag, data, children)
}

(2)vue-route

在Vue在路由创建模式中,也多次用到了工厂模式:

export default class VueRouter {constructor(options) {this.mode = mode    // 路由模式switch (mode) {           // 简单工厂case 'history':       // history 方式this.history = new HTML5History(this, options.base)breakcase 'hash':          // hash 方式this.history = new HashHistory(this, options.base, this.fallback)breakcase 'abstract':      // abstract 方式this.history = new AbstractHistory(this, options.base)breakdefault:// ... 初始化失败报错}}
}

mode 是路由创建的模式,这里有三种 History、Hash、Abstract,其中,History 是 H5 的路由方式,Hash 是路由中带 # 的路由方式,Abstract 代表非浏览器环境中路由方式,比如 Node、weex 等;this.history 用来保存路由实例,vue-router 中使用了工厂模式的思想来获得响应路由控制类的实例。

【3】策略模式
1. 什么是策略模式?

策略模式 (Strategy Pattern)又称政策模式,其定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。关键是策略的实现和使用分离。

2.策略模式的实际应用

(1)表格 formatter

Element UI 的表格控件的 Column 接受一个 formatter 参数,用来格式化内容,其类型为函数,并且还可以接受几个特定参数,像这样:Function(row, column, cellValue, index)。

以文件大小转化为例,后端经常会直接传 bit 单位的文件大小,那么前端需要根据后端的数据,根据需求转化为自己需要的单位的文件大小,比如 KB/MB。

首先实现文件计算的算法:

export const StrategyMap = {// Strategy 1: 将文件大小(bit)转化为 KB bitToKB: val => {const num = Number(val)return isNaN(num) ? val : (num / 1024).toFixed(0) + 'KB'},// Strategy 2: 将文件大小(bit)转化为 MB bitToMB: val => {const num = Number(val)return isNaN(num) ? val : (num / 1024 / 1024).toFixed(1) + 'MB'}
}
// Context: 生成el表单 formatter 
const strategyContext = function(type, rowKey){ return function(row, column, cellValue, index){StrategyMap[type](row[rowKey])}
}
export default strategyContext

在组件中直接使用:

<template><el-table :data="tableData"><el-table-column prop="date" label="日期"></el-table-column><el-table-column prop="name" label="文件名"></el-table-column><!-- 直接调用 strategyContext --><el-table-column prop="sizeKb" label="文件大小(KB)":formatter='strategyContext("bitToKB", "sizeKb")'></el-table-column><el-table-column prop="sizeMb" label="附件大小(MB)":formatter='strategyContext("bitToMB", "sizeMb")'></el-table-column></el-table>
</template>
<script type='text/javascript'>import strategyContext from './strategyContext.js'export default {name: 'ElTableDemo',data() {return {strategyContext,tableData: [{ date: '2019-05-02', name: '文件1', sizeKb: 1234, sizeMb: 1234426 },{ date: '2019-05-04', name: '文件2', sizeKb: 4213, sizeMb: 8636152 }]}}}
</script>
<style scoped></style>

运行结果如下图
在这里插入图片描述

(2)表单验证

除了表格中的 formatter 之外,策略模式也经常用在表单验证的场景。Element UI 的 Form 表单 具有表单验证功能,用来校验用户输入的表单内容。实际需求中表单验证项一般会比较复杂,所以需要给每个表单项增加 validator 自定义校验方法。

实现通用的表单验证方法:

// src/utils/validates.js
// 姓名校验 由2-10位汉字组成 
export function validateUsername(str) {const reg = /^[\u4e00-\u9fa5]{2,10}$/return reg.test(str)
}
// 手机号校验 由以1开头的11位数字组成  
export function validateMobile(str) {const reg = /^1\d{10}$/return reg.test(str)
}
// 邮箱校验 
export function validateEmail(str) {const reg = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/return reg.test(str)
}

增加一个柯里化方法,用来生成表单验证函数:

// src/utils/index.js
import * as Validates from './validates.js'
// 生成表格自定义校验函数 
export const formValidateGene = (key, msg) => (rule, value, cb) => {if (Validates[key](value)) {cb()} else {cb(new Error(msg))}
}

具体使用:

<template><el-form ref="ruleForm"label-width="100px"class="demo-ruleForm":rules="rules":model="ruleForm"><el-form-item label="用户名" prop="username"><el-input v-model="ruleForm.username"></el-input></el-form-item><el-form-item label="手机号" prop="mobile"><el-input v-model="ruleForm.mobile"></el-input></el-form-item><el-form-item label="邮箱" prop="email"><el-input v-model="ruleForm.email"></el-input></el-form-item></el-form>
</template>
<script type='text/javascript'>import * as Utils from '../utils'export default {name: 'ElTableDemo',data() {return {ruleForm: { pass: '', checkPass: '', age: '' },rules: {username: [{validator: Utils.formValidateGene('validateUsername', '姓名由2-10位汉字组成'),trigger: 'blur'}],mobile: [{validator: Utils.formValidateGene('validateMobile', '手机号由以1开头的11位数字组成'),trigger: 'blur'}],email: [{validator: Utils.formValidateGene('validateEmail', '不是正确的邮箱格式'),trigger: 'blur'}]}}}}
</script>

效果如图:
在这里插入图片描述

【4】代理模式
1. 什么是代理模式?

代理模式 (Proxy Pattern)又称委托模式,它为目标对象创造了一个代理对象,以控制对目标对象的访问。

代理模式把代理对象插入到访问者和目标对象之间,从而为访问者对目标对象的访问引入一定的间接性。正是这种间接性,给了代理对象很多操作空间,比如在调用目标对象前和调用后进行一些预操作和后操作,从而实现新的功能或者扩展目标的功能。

2.代理模式在实战中的应用

(1)拦截器

在项目中经常使用 Axios 的实例来进行 HTTP 的请求,使用拦截器 interceptor 可以提前对 request 请求和 response 返回进行一些预处理,比如:
1、request 请求头的设置,和 Cookie 信息的设置;
2、权限信息的预处理,常见的比如验权操作或者 Token 验证;
3、数据格式的格式化,比如对组件绑定的 Date 类型的数据在请求前进行一些格式约定好的序列化操作;
4、空字段的格式预处理,根据后端进行一些过滤操作;
5、response 的一些通用报错处理,比如使用 Message 控件抛出错误;
除了 HTTP 相关的拦截器之外,还有路由跳转的拦截器,可以进行一些路由跳转的预处理等操作。

(2)前端框架的数据响应式化

Vue 2.x 中通过 Object.defineProperty 来劫持各个属性的 setter/getter,在数据变动时,通过发布-订阅模式发布消息给订阅者,触发相应的监听回调,从而实现数据的响应式化,也就是数据到视图的双向绑定。

为什么 Vue 2.x 到 3.x 要从 Object.defineProperty 改用 Proxy 呢,是因为前者的一些局限性,导致的以下缺陷
1、无法监听利用索引直接设置数组的一个项,例如:vm.items[indexOfItem] = newValue;
2、无法监听数组的长度的修改,例如:vm.items.length = newLength;
3、无法监听 ES6 的 Set、WeakSet、Map、WeakMap 的变化;
4、无法监听 Class 类型的数据;
5、无法监听对象属性的新加或者删除;

【5】适配器模式
1. 什么是适配器模式?

适配器模式(Adapter Pattern)又称包装器模式,将一个类(对象)的接口(方法、属性)转化为用户需要的另一个接口,解决类(对象)之间接口不兼容的问题。

主要功能是进行转换匹配,目的是复用已有的功能,而不是来实现新的接口。也就是说,访问者需要的功能应该是已经实现好了的,不需要适配器模式来实现,适配器模式主要是负责把不兼容的接口转换成访问者期望的格式而已。

2.适配器的实际案例

(1)Vue 计算属性

Vue 中的计算属性也是一个适配器模式的实例,以官网的例子为例:

<template><div id="example"><p>Original message: "{{ message }}"</p>  <!-- Hello --><p>Computed reversed message: "{{ reversedMessage }}"</p>  <!-- olleH --></div>
</template>
<script type='text/javascript'>export default {name: 'demo',data() {return {message: 'Hello'}},computed: {reversedMessage: function() {return this.message.split('').reverse().join('')}}}
</script>

对原有数据并没有改变,只改变了原有数据的表现形式。

(2) 源码中的适配器模式

Axios 的用来发送请求的 adapter 本质上是封装浏览器提供的 API XMLHttpRequest。

module.exports = function xhrAdapter(config) {return new Promise(function dispatchXhrRequest(resolve, reject) {var requestData = config.datavar requestHeaders = config.headersvar request = new XMLHttpRequest()// 初始化一个请求request.open(config.method.toUpperCase(),buildURL(config.url, config.params, config.paramsSerializer), true)// 设置最大超时时间request.timeout = config.timeout// readyState 属性发生变化时的回调request.onreadystatechange = function handleLoad() { ... }// 浏览器请求退出时的回调request.onabort = function handleAbort() { ... }// 当请求报错时的回调request.onerror = function handleError() { ... }// 当请求超时调用的回调request.ontimeout = function handleTimeout() { ... }// 设置HTTP请求头的值if ('setRequestHeader' in request) {request.setRequestHeader(key, val)}// 跨域的请求是否应该使用证书if (config.withCredentials) {request.withCredentials = true}// 响应类型if (config.responseType) {request.responseType = config.responseType}// 发送请求request.send(requestData)})
}

这个模块主要是对请求头、请求配置和一些回调的设置,并没有对原生的 API 有改动,所以也可以在其他地方正常使用。这个适配器可以看作是对 XMLHttpRequest 的适配,是用户对 Axios 调用层到原生 XMLHttpRequest 这个 API 之间的适配层。

【5】观察者模式/发布-订阅模式
1. 什么是观察者模式?

观察者模式(Observer Pattern)定义了一种一对多的关系,让多个订阅者对象同时监听某一个发布者,或者叫主题对象,这个主题对象的状态发生变化时就会通知所有订阅自己的订阅者对象,使得它们能够自动更新自己。

2. 什么是发布-订阅模式?

其实它是发布订阅模式的一个别名,但两者又有所不同。这个别名非常形象地诠释了观察者模式里两个核心的角色要素——发布者和订阅者。
发布-订阅模式有一个调度中心
在这里插入图片描述
观察者模式是由具体目标调度的,而发布-订阅模式是统一由调度中心调的

3.Vue中的发布-订阅模式

(1)EventBus

在Vue中有一套事件机制,其中一个用法是 EventBus。可以使用 EventBus 来解决组件间的数据通信问题。
1.创建事件中心管理组件之间的通信

// event-bus.js
import Vue from 'vue'
export const EventBus = new Vue()

2.发送事件

<template><div><first-com></first-com><second-com></second-com></div>
</template>
<script>
import firstCom from './firstCom.vue'
import secondCom from './secondCom.vue'
export default {components: { firstCom, secondCom }
}
</script>

firstCom组件中发送事件:

<template><div><button @click="add">加法</button>    </div>
</template>
<script>
import {EventBus} from './event-bus.js' // 引入事件中心
export default {data(){return{num:0}},methods:{add(){EventBus.$emit('addition', {num:this.num++})}}
}
</script>

3.接收事件
在secondCom组件中发送事件:

<template><div>求和: {{count}}</div>
</template>
<script>
import { EventBus } from './event-bus.js'
export default {data() {return {count: 0}},mounted() {EventBus.$on('addition', param => {this.count = this.count + param.num;})}
}
</script>

(2)Vue源码

发布-订阅模式在源码中应用很多,比如双向绑定机制的场景
图片
响应式化大致就是使用 Object.defineProperty 把数据转为 getter/setter,并为每个数据添加一个订阅者列表的过程。这个列表是 getter 闭包中的属性,将会记录所有依赖这个数据的组件。也就是说,响应式化后的数据相当于发布者。

每个组件都对应一个 Watcher 订阅者。当每个组件的渲染函数被执行时,都会将本组件的 Watcher 放到自己所依赖的响应式数据的订阅者列表里,这就相当于完成了订阅,一般这个过程被称为依赖收集(Dependency Collect)。

组件渲染函数执行的结果是生成虚拟 DOM 树(Virtual DOM Tree),这个树生成后将被映射为浏览器上的真实的 DOM树,也就是用户所看到的页面视图。

当响应式数据发生变化的时候,也就是触发了 setter 时,setter 会负责通知(Notify)该数据的订阅者列表里的 Watcher,Watcher 会触发组件重渲染(Trigger re-render)来更新(update)视图。

Vue 的源码:

// src/core/observer/index.js 响应式化过程
Object.defineProperty(obj, key, {enumerable: true,configurable: true,get: function reactiveGetter() {// ...const value = getter ? getter.call(obj) : val // 如果原本对象拥有getter方法则执行dep.depend()                     // 进行依赖收集,dep.addSubreturn value},set: function reactiveSetter(newVal) {// ...if (setter) { setter.call(obj, newVal) }    // 如果原本对象拥有setter方法则执行dep.notify()               // 如果发生变更,则通知更新}
})

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT笔记——QtPropertyBrowser的使用

上一节&#xff0c;我们将了如何去配置QtPropertyBrowser 本节&#xff0c;我们将说明 如何 去 使用QtPropertyBrowser 这个属性类的一些基本知识 简单的几种用法&#xff1a; 首先&#xff1a; 我们需要创建一个Widget 提升一个类 为 QtTreePropertyBrowser .h文件 QtVariant…

详解客户关系管理系统

一、客户关系管理系统的重要性 客户关系管理系统&#xff0c;是指利用软件、硬件和网络技术&#xff0c;为企业建立一个客户信息收集、管理、分析和利用的信息系统。以客户数据的管理为核心&#xff0c;记录企业在市场营销和销售过程中和客户发生的各种交互行为&#xff0c;以…

华为C++研发工程师编程题 ACM模式输入输出|| 1.汽水瓶,2.明明的随机数,3.进制转换

C ACM输入输出 1.汽水瓶题目描述思路代码如下 2.明明的随机数题目描述思路&#xff1a;代码如下&#xff1a; 3.进制转换题目描述思路&#xff1a;代码如下 题目链接&#xff1a; 华为研发工程师编程题 1.汽水瓶 题目描述 某商店规定&#xff1a;三个空汽水瓶可以换一瓶汽水…

服务器空间不足处理与解决思路—实战docker占用空间太大

前言 服务器Centos操作系统&#xff0c;空间不足的问题处理了三次了&#xff0c;决定把它的解决思路和处理过程记录下来。服务器空间不足是一个经常会遇到的问题&#xff0c;尤其是在大型应用程序和网站上。当服务器空间不足时&#xff0c;应该采取一些步骤来处理和解决这个问…

LeetCode:206. 反转链表

&#x1f34e;道阻且长&#xff0c;行则将至。&#x1f353; &#x1f33b;算法&#xff0c;不如说它是一种思考方式&#x1f340; 算法专栏&#xff1a; &#x1f449;&#x1f3fb;123 一、&#x1f331;206. 反转链表 题目描述&#xff1a;给你单链表的头节点 head &#x…

html学习(布局方式(layout)、浮动(float)、定位(position)、弹性盒(flex))

布局方式(layout) 文档流 文档流&#xff08;normal flow&#xff09; 文档流通俗的讲&#xff0c;就是一个web页面中&#xff0c;每一个模块只能从上到下从左往右的方式排列在页面上。 将窗口自下而上分成一行一行&#xff0c;应在每行中按从左至右的依次排放元素&#xff0…

光纤网卡传输速率和它的应用领域有哪些呢?通常会用到哪些型号网络变压器呢?

Hqst盈盛&#xff08;华强盛&#xff09;电子导读&#xff1a;常有客户问起光纤网卡该如何选用到合适的产品&#xff0c;选用时要注意到哪些事项&#xff0c;这节将结合配合到的网络变压器和大家一起探讨&#xff0c;希望对大家有些帮助。 1&#xff0e;光纤网卡传输速率与网络…

【iOS-分类,拓展和关联对象底层探究】

前言 寒假分享会问题解决二 早在大一的OC的学习过程就知道了分类和拓展的区别和联系&#xff0c;分类不能添加成员变量&#xff0c;而拓展可以添加成员变量。分类是在运行时期实现的&#xff0c;而拓展只是编译器的时候就实现了。对于分类我们可以通过关联对象来为我们需要的分…

线程池四种拒绝机制 实现 及执行日志

目录 目录 目录 创建线程池 测试代码 运行线程 全量代码 日志 AbortPolicy 报出异常模式 DiscardPolicy 放弃机制啥也不处理 DiscardOldestPolicy 放弃机制&#xff0c;放弃列队最早进入的 CallerRunsPolicy 交给主线程执行 创建线程池 public static ExecutorServi…

项目范围控制:如何控制项目范围的变化?

一个成功的项目需要在进度、成本和质量之间取得平衡。控制项目交付范围是实现这个平衡的关键。然而&#xff0c;项目范围是会变化的&#xff0c;因此控制项目范围变化是必要的。 如何控制项目范围的变化&#xff1f; 1、了解项目的交付范围 项目经理、团队成员、利益相关者和…

我用什么写Python?

入门教程、案例源码、学习资料、读者群 请访问&#xff1a; python666.cn 大家好&#xff0c;欢迎来到 Crossin的编程教室 &#xff01; 通常来说&#xff0c;每个程序员都有自己趁手的兵器&#xff1a;代码编辑器。你要是让他换个开发环境&#xff0c;恐怕开发效率至少下降三成…

c/c++:char*定义常量字符串,strcmp()函数,strcpy()函数,寻找指定字符,字符串去空格

c/c&#xff1a;char*定义常量字符串&#xff0c;strcmp()函数&#xff0c;strcpy()函数&#xff0c;寻找指定字符&#xff0c;字符串去空格 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;此时学会c的话&#xff0c; 我所…

Python爬虫基础之二

Python爬虫基础包括HTTP协议、HTML、CSS和JavaScript语言基础、requests库的使用、Beautiful Soup库的使用、xpath和正则表达式的使用等。此外&#xff0c;还应该了解反爬虫机制和爬虫的一些常见问题及解决方法。 上一篇文章讲解了有关条件判断语句、循环语句等相关知识&#…

陆奇-奇绩创坛-chatGPT新范式,新时代,新机会

奇绩创坛-新范式&#xff0c;新时代&#xff0c;新机会 01-新范式 新范式的新拐点 新范式的历史环境 新范式的社会影响 新范式的缔造者&#xff1a;Sam Altman和OpenAI 新范式的动力引擎 新范式的演化路径 02-新时代 新时代的宏观发展格局 新时代的中国机会 新时代的OpenAI生…

IT项目管理之软件测试

1. 定义 软件测试是使用人工或者自动的手段来运行或者测定某个软件系统的过程&#xff0c;其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别。 在软件投入使用前&#xff0c;要经过一系列的严格测试&#xff0c;才能保证交付质量。 2. QC & QA &a…

开源模型ModelScope的初探使用

泛AI开发者的一站式模型服务产品平台 阿里达摩院推出了一个开源的模型共享平台&#xff0c;包括计算机视觉、多模态、自然语言处理等多个领域上手即用的模型&#xff0c;如果AI相关模型感兴趣的同学&#xff0c;或者想基于基础模型做业务场景的同学&#xff0c;都可以用这个平…

C++三大特性—继承 “访问控制”

本文主要阐述关于C继承中基类与派生类之间的访问关系 继承方式与访问方式 继承定义格式&#xff1a; 派生类可以继承定义在基类的成员&#xff0c;但是派生类的成员函数不一定有权访问从基类继承来的成员    访问限定符的作用&#xff1a;控制派生类从基类继承而来的成员是否…

学习系统编程No.23【信号实战】

引言&#xff1a; 北京时间&#xff1a;2023/4/23&#xff0c;最近学习状态不怎么好&#xff0c;总是犯困&#xff0c;没精力的感觉&#xff0c;可能是病没有好彻底的原因&#xff0c;也可能是我内心因为生病而认为摆烂理所应当&#xff0c;反正最后导致摆烂&#xff0c;课现在…

android之 Launcher改造仿桌面排版的效果

一&#xff0c;背景 1.1 新接手一个灯光控制项目&#xff0c;其页面和效果还是比交复杂的&#xff0c;其中一个功能就是仿苹果桌面来排版灯具&#xff0c;支持拖拽&#xff0c;分组&#xff0c;分页。 拖动图标的时候判断是否空白位置还是已经有占位了&#xff0c;有的话就把…

体验了多款国产类ChatGPT产品后,我选择了道合顺的【ChatIC】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后端的开发语言A…