跟新中….
为什么要使用装饰者模式 Decorator Pattern 装饰者模式,动态的透明的增加一些另外的功能而不需要改变原来的代码,拥有更好的灵活性和可扩展性
从名字中也可以看出,装饰者模式就是给一个对象加上一层装饰,穿上一件衣服,装饰者在我解除的技术里面在函数式语言中的应用比较广泛,就是在装饰函数里传入一个目标函数,装饰函数同样返回一个目标函数,但是返回的函数是进过装饰了的
使用装饰者模式可以不改变原来的代码而增加一些额外的功能,讲增加的功能和原来的功能代码解耦了,代码可移植性更强了,原来代码还可以用在其他地方其他项目或则增加另外的装饰来实现更多的功能
在Java中的应用和实现 实现案例 下面先来看一个 Shape 自己实现的案例:
Shape顶层接口:
public interface Shape { String display(); } Circle和Rectangle具体实现
public class Circle implements Shape{ private String name; public Circle(){ this.name = "Circle"; } public String display() { return this.name; } } ------------------------------------------------ public class Rectangle implements Shape { private String name; public Rectangle() { this.name = "Rectangle"; } public String display() { return this.name; } } 所有装饰器的顶层抽象对象,这里通过构造方法和set方法可以传入被装饰对象
MySql字符集 MySql支持很多字符集,可以使用如下命令查看MySql支持的字符集:
SHOW CHARACTER SET SHOW CHARSET SHOW CHARACTER SET LIKE 'utf8%' 其中Default collation 表示默认的 比较规则 MAXlen表示最大长度(单位byte)
下面是几个重要的字符集的最大长度
字符集名称 Maxlen ascii 1 gbk 2 utf8(阉割版UTF8,不包含特殊字符如表情字符等) 3 utf8mb4 4
utf8和utf8mb4 utf8是utf8mb3的别名,只支持最大长度是3byte,属于 阉割版 的UTF8字符集
utf8mb4 是完整的UTF8字符集,最大支持4byte,包含所有UTF8字符集,所以如果文本里面有特殊符号或则表情符号,比如评论的内容附带表情的就需要修改表的字符集为utf8mb4
字符集比较规则 字符集比较规则用于字符集比较,比如a、A两个比较是按照ASCII码大小来比较还是忽略大小写进行比较,可以使用如下命令显示支持的比较规则
SHOW COLLATION #显示所有比较规则 SHOW COLLATION LIKE '%utf8%' utf8默认的比较规则就是utf8_general_ci
utf8mb4默认是utf8mb4_0900_ai_ci
以ci结尾的比较规则都是忽略大小写的,如果需要区分大小写则使用utf8_bin比较规则
字符集和比较规则应用范围 1、字符集的三大范围 服务器级别 数据库级别 表级别 列级别 2、服务器级别 系统变量 描述 character_set_server 服务器级别的字符集 collation_server 服务器级别的比较规则 可以在配置文件里配置服务器的字符集和比较规则
[server] character_set_server=gbk collation_server=gbk_chinese_ci 3、数据库、表、字段级别 数据库级别的字符集和比较规则可以在建库的时候指定,如果没有指定则默认和服务器级别的字符集一样
系统变量 描述 character_set_database 数据库级别的字符集 collation_database 数据库级别的比较规则 CREATE DATABASE mydb CHARACTER SET utf8 COLLATE utf8_general_ci 库的字符集变量是只读的,只能在创建库的时候指定或则使用ALTER指令修改
go中的测试 go的测试是是以 xxx_test.go结尾的,前面的名字和对应的测试文件名字一样,后面加个test,运行测试命令之后就会扫描所有测试文件进行测试
xxx_test.go测试文件中主要有如下几个部分:
类型 格式 作用 单元测试 函数名前缀为Test 测试程序的一些逻辑行为是否正确 基准测试 函数名前缀为Benchmark 测试函数的性能 示例代码 函数名前缀为Example 为文档提供示例文档
单元测试 $ go test -v #扫描当前包下所有的测试文件进行测试 并且输出详细信息 $ go test -v -test.run A #测试包含 A 字母的单元测试函数 [只能运行单元测试] 单元测试函数必须以 t *testing为参数,t主要用于报告测试结果是否正确以及日志记录,主要有如下几个方法:
Error Log 最常用
//标记失败 func (c *T) Fail() //标记失败,但继续执行当前测试函数 func (c *T) FailNow() //标记失败,停止下面的执行 func (c *T) Failed() bool //日志信息 go test如果测试成功的话,不会打印这部分内容,加上 -v则测试成功也会显示 func (c *T) Log(args ...interface{}) func (c *T) Logf(format string, args .
基本用法 go随机数在math/rand包下,go的随机数需要先给他一个Seed,Seed如果一样的话或则不设置的话每次生成的都是 伪随机数 ,多次执行生成的都是一样的随机数序列,所以必须设定Seed而且还是以 时间戳 的方式来设置,如下生成 [0,10)之间的随机整数:
rand.Seed(time.Now().UnixNano()) r:=rand.Intn(10) //[0,10) 返回int类型 r=rand.Int63n(10) //返回int64 如果要生成指定范围的随机整数,如下生成[min,max)之间的随机整数:
rand.Seed(time.Now().UnixNano()) max:=10;min:=-10 rand.Intn(max-min)+min //[-10,10)
随机负载均衡实现 我们实战一下,实现一个 随机数负载均衡
type RandomBalance struct { curIndex int hosts []string } func (r *RandomBalance) Add(host string) { r.hosts = append(r.hosts, host) } func (r *RandomBalance) Next() (string, error) { if len(r.hosts) == 0 { return "", errors.New("no host") } rand.Seed(time.Now().UnixNano()) r.curIndex = rand.Intn(len(r.hosts)) return r.hosts[r.curIndex], nil } func main() { rb := RandomBalance{} for i := 1; i < 10; i++ { rb.
配置步骤 ubuntu阿里镜像站:http://mirrors.aliyun.com/ubuntu-releases/
ubuntu配置阿里云软件源:https://developer.aliyun.com/mirror/ubuntu?spm=a2c6h.13651102.0.0.3e221b11Zy3CPT
更新软件源头
$ apt update 重置root密码:
$ su passwd 设置允许以root身份ssh登入,设置PermitRootLogin yes:
$ vim /etc/ssh/sshd_config #设置PermitRootLogin yes $ service ssh restart #重启ssh服务 静态IP和网络相关的设置
$ vim /etc/netplan/00-installer-config.yaml ---------------------------------------------- # This is the network config written by 'subiquity' network: ethernets: ens33: #网卡名字 addresses: - 192.168.1.10/24 #IP dhcp4: false #关闭DHCP gateway4: 192.168.1.1 #设置网关 4表示ipv4 nameservers: #设置DNS addresses: - 192.168.1.1 version: 2 ------------------------------------------------- $ netplan apply #应用配置 发送宿主机公钥给vmware虚拟机,允许宿主机免密登入虚拟机
ssh-copy-id -i ~/.ssh/id_rsa.pub root@u
Go modules相关的环境变量 GO111MODULE="on" #是否启用go module go1.16默认开启 GOPROXY="https://goproxy.io,direct" #go拉去依赖的镜像站点 GOPRIVATE="" #私有go仓库相关配置 上面的环境变量可以使用下面的命令进行改写
go env -w GO111MODULE=on 或则直接设置环境变量
GO111MODULE=on
go.mod文件 //每个模块都有一个名字,通常通过go mod init指定 module github.com/biningo/go-play //指定go版本 go 1.15 //指定依赖的库地址 <url> <version> 形式 require ( github.com/gin-gonic/gin v1.6.3 ) //replace 替换 require 中声明的依赖,使用另外的依赖及其版本号 不经常使用 replace github.com/gin-gonic/gin v1.6.3 => github.com/gin-gonic/gin v1.6.2 //exclude 排除某些版本 exclude ithub.com/gin-gonic/gin v1.5.0 模块名字主要有如下几个作用:
作为模块的标识 作为模块的 import path,go会根据此导入到$GOPATH/pkg/mod路径下去寻找代码 go mod的replace命令主要用来替换原来的包,使用场景有如下几个
单纯的替换包 替换无法下载的包
go.sum文件 该文件记录格式如下
# <module> <version>/go.mod <hash> github.com/gin-gonic/gin v1.6.3/go.mod h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= 后面的hash就是go get命令生成的对代码压缩包的hash值
defer执行时机 for i:=1;i<10;i++{ defer log.Println(i) } 上面那段简单的代码基本就可以说明多个defer时的执行顺序了
当代码中出现defer时,会将defer要执行的函数压人栈,然后等函数执行完毕再执行defer栈中的内容
go1.13以前用堆分配,加入到链表中,再尾递归调用,go1.13在栈上分配,如果defer过多则还是会在堆上用链表来管理
go1.14则做了进一步优化,defer的开销基本很小了
defer的估值时刻 defer分为进入阶段和退出阶段 ,defer延迟的只是函数体的执行,并不延迟函数的初始化
//defer初始化值和位置有关 推迟执行的仅仅是函数体 func main(){ j:=10 defer func(jj int) { log.Printf("j=%d jj=%d\n",j,jj) //j=99 jj=10 }(j) //传入10 j=99 }
防止defer内存泄漏 下面这段代码会严重占用内存栈,造成短暂内存泄漏,有大量的文件句柄没有被释放
//内存泄漏 func writeManyFiles(files []os.File) error { for _, file := range files { //...... defer file.Close() } return nil } 用函数包裹之后每循环一个就关闭一个文件句柄
//防止内存泄漏 func writeManyFiles(files []os.File) error { for _, file := range files { if err:= func() error { f, err := os.
godoc godoc -http=:8000 #开启本地文档服务器
Go文档注释规范 因为go的注释即文档,文档都是根据注释生成的,所以文档的详细性和合理性都必须要求注释必须符合一定的规范,这样才可以生成漂亮详细的文档
文档主要有如下几部分组成:
组成 作用 Overview 包含包的 import 语句和概要说明 Index 包含包中可见性为 public 的常量、类型、方法、函数的总目录及说明 Constants 项目所有的导出常量 Variables 显示所有全局变量 Functions 显示所有函数 Types 显示所有type Overview 用于整个项目的简单描述,又叫包文档
项目中一级目录下所有包头开始的注释内容的合并,这里需要注意注释和包名一行必须没有空格
一般如果包注释需要特别多的话则会将这些信息单独写在doc.go文件中,此文件专门用来记录包的描述信息,比如gin的doc.go下的内容为
/* Package gin implements a HTTP web framework called gin. See https://gin-gonic.com/ for more information about gin. */ package gin // import "github.com/gin-gonic/gin" doc.go专门用于存放项目的Overview信息,不用于存放代码
Index 该项目列出了所有导出的结构体、函数、常量等名字以及超链接,用于索引该项目的所有函数、结构体等对象,其详细内容在相应的详细内容上,点击链接就可以看到具体函数详细的注释内容
Constants const不可变得常量,需要注释在const之上
//My Name const ( NAME="lyer" AGE=18 ) Variables var全局变量,和const注释规则一致
//My Name var( NAME="lyer" AGE=18 ) 具体内容注释 比如有一个函数、结构体、常量、全局变量等,注释在函数声明的上面,并且不能有空行这样才会显示在文档上,结构体也仅仅会展示公共属性
配置zsh 安装zsh apt install zsh 安装oh-my-zsh #https://github.com/ohmyzsh/ohmyzsh sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" 运行上面的sh之后,就会在家目录下配置.zshrc文件,当然也可以手动clone仓库代码到,然后按照oh-my-zsh模板文件进行配置.zshrc
配置.zshrc 该文件的作用和.bashrc作用一样,为了不让之前.bashrc的命令失效,可以在.zshrc中source进来,下面展示主要配置
#配置终端主题,不然会很丑 主题路径在.oh-my-zsh/themes 可以修改主题的样式 ZSH_THEME="robbyrussell" #配置zsh插件 有些系统自带的插件则直接配置即可 #有些外部插件则需要下载(clone)到 .oh-my-zsh/custom/plugins路径下 然后需要在下面写上名字即可 plugins=( git zsh-syntax-highlighting #shell命令高亮插件 colored-man-pages #系统自带 zsh-autosuggestions #命令提示插件 ) 可以为zsh也配置wakatime来统计你在终端上的时间
https://github.com/sobolevn/wakatime-zsh-plugin pip install wakatime waketime的python cli程序也需要安装,其地址如下:
https://github.com/wakatime/wakatime
配置tmux 安装tmux apt install tmux 修改配置文件 tmux的配置文件在~/.tmux.conf
个人觉得tmux默认的快捷键不符合自己,那么可以修改,下面展示我的配置文件
#设置快捷键前缀 set -g prefix C-a #修改快捷键前缀 我习惯与ctrl+a unbind C-b # 解绑默认的 ctrl+b 前缀快捷键 bind C-a send-prefix # 绑定Ctrl+a为新的指令前缀 #绑定方向键 bind -r k select-pane -U # 绑定k为↑ bind -r j select-pane -D # 绑定j为↓ bind -r h select-pane -L # 绑定h为← bind -r l select-pane -R # 绑定l为→ #切换切割pane按键 分割窗口要用到 unbind '"' #解绑默认的键 # 垂直方向新增面板,默认进入当前目录 bind ] splitw -v -c '#{pane_current_path}' unbind % # 水平方向新增面板,默认进入当前目录 bind [ splitw -h -c '#{pane_current_path}' tmux的基本命令这里分享一个链接,可以速查一些相关的命令: https://gist.
head标签 head标签用于HTML文档头部,主要用于存放元数据、引入外部样式脚本等标签的容器,还可定义一些页面信息相关的内容,主要的子标签如下:
<meta>:设置网页的元数据,比如网页的字符集…..
<link>:引入外部资源,指定ref定义当前文档与被链接文档之间的关系
指定type定义被链接的文档类型
<title>:设置网页标题
<style>:放置内嵌的样式表
<script>:引入外部js脚本
<head> <meta charset="UTF-8"> <title>这是网页标题</title> <link rel="stylesheet" type="text/css" href="theme.css"> <link rel="stylesheet" type="text/css" href="http://www.x.cn/a.css"> <style> a{color: red;} </style> <script src="https://static.sick.cn/respond.min.js"></script> //下面脚本会执行 <script> alert("hello,world") </script> //定义了这行则所有绝对地址的url则都会以这个为基础 <base href="https://www.google.com"> </head>
meta元数据 meta标签用于设置一些元数据,并且可以定义一些浏览器的缓存策略,还可以定义网页关键字用于搜索引擎爬虫的爬取
<!-- 定义网页文档的字符集 --> <meta charset="utf-8" /> <!-- 网页作者 --> <meta name="author" content="开源技术团队"/> <!-- 网页地址 --> <meta name="website" content="https://www.baidu.com"/> <!-- 网页版权信息 --> <meta name="copyright" content="2020-2021 demo.com"/> <!-- 网页关键字, 用于SEO --> <meta name="keywords" content="meta,html"/> <!-- 网页描述 --> <meta name="description" content="网页描述"/> <!