PHP代码总结:时间处理相关的辅助类

PHPzkbhj 发表了文章 • 0 个评论 • 46 次浏览 • 2019-05-30 14:49 • 来自相关话题

class TimeHelper
{
/**
* 得到当前时间的毫秒时间戳
* @return float 13位毫秒时间戳
*/
public static function getCurTimeMsec()
{
list($t1, $t2) = explode(' ', microtime());
return (float)sprintf('%.0f',(floatval($t1)+floatval($t2))*1000);
}

/**
* 获取当前时间17位的毫秒时间格式时间点(2017 07 29 21 44 43 129)
* @return integer
*/
public static function getCurTimeMsecFormat()
{
list($u_sec, $sec) = explode(' ', microtime());
return intval(date('YmdHis', intval($sec)) . str_pad(round(floatval($u_sec) * 1000), 3, 0, STR_PAD_LEFT));
}

/**
* 将20200629000000格式的日期转换成0000-00-00 00:00:00格式
*/
public static function dateNormalization($date)
{
if (strlen($date) == 14) {
return preg_replace('/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', "$1-$2-$3 $4:$5:$6", $date);
}
return $date;
}

/**
* 将17位的毫秒时间格式(2017 07 29 21 44 43 129)转换成毫秒时间戳格式(15XXX)
*/
public static function dateToMescNormalization($date)
{
if (strlen($date) == 17) {
$secDate = preg_replace('/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', "$1-$2-$3 $4:$5:$6", substr($date,0,14));
return strtotime($secDate).substr($date,14,3);
}
return $date;
}
} 查看全部
class TimeHelper
{
/**
* 得到当前时间的毫秒时间戳
* @return float 13位毫秒时间戳
*/
public static function getCurTimeMsec()
{
list($t1, $t2) = explode(' ', microtime());
return (float)sprintf('%.0f',(floatval($t1)+floatval($t2))*1000);
}

/**
* 获取当前时间17位的毫秒时间格式时间点(2017 07 29 21 44 43 129)
* @return integer
*/
public static function getCurTimeMsecFormat()
{
list($u_sec, $sec) = explode(' ', microtime());
return intval(date('YmdHis', intval($sec)) . str_pad(round(floatval($u_sec) * 1000), 3, 0, STR_PAD_LEFT));
}

/**
* 将20200629000000格式的日期转换成0000-00-00 00:00:00格式
*/
public static function dateNormalization($date)
{
if (strlen($date) == 14) {
return preg_replace('/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', "$1-$2-$3 $4:$5:$6", $date);
}
return $date;
}

/**
* 将17位的毫秒时间格式(2017 07 29 21 44 43 129)转换成毫秒时间戳格式(15XXX)
*/
public static function dateToMescNormalization($date)
{
if (strlen($date) == 17) {
$secDate = preg_replace('/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/', "$1-$2-$3 $4:$5:$6", substr($date,0,14));
return strtotime($secDate).substr($date,14,3);
}
return $date;
}
}

#自学课程#《放学你别走第一季之GO语言学习》Day4打卡

GoLangzkbhj 发表了文章 • 0 个评论 • 135 次浏览 • 2019-02-25 10:13 • 来自相关话题

【Day4任务】
学习GO语言组织数据的容器:数组,切片,映射,列表以及结构体。
用学到的知识实现下面的题目:
设计一个程序,可以录入、读取和删除房源数据,房源数据包括房源名称,房源编号,房源价格(正整数),房源面积(浮点数),是否是首次出租(布尔类型),房源标签(新校区,进地铁,深呼吸,独立卫生间等不限)。
读取房源时通过房源编号读取信息。
打卡时间:2月24日(周日)23:30前
打卡形式:代码运行截图+代码源码
package main

import (
"fmt"
"os"

)

//定义房源结构体
type house struct {
houseCode string
price int
area float64
isNew bool
tags string
}

var (
houseCode string
price int
area float64
isNewName string
isNew bool
tags string
)

func help(){

fmt.Println("请按照提示信息录入房源数据,并根据房源编号显示房源数据:")

}

func line() {
fmt.Println("*********************************")

}

func menu() {
fmt.Println("*********************************")
fmt.Println("1、查询房源(Select)")
fmt.Println("2、新增房源(Insert)")
fmt.Println("3、删除房源(Delete)")
fmt.Println("4、帮助信息(Help)")
fmt.Println("5、统计房源数量(Counts)")
fmt.Println("6、退出程序(Exit)")
fmt.Println("*********************************")

}

func errorHappen(no int) {

switch no {

case 1:
fmt.Println("参数错误!更多帮助信息请使用参数'help'!")

case 2:
fmt.Println("该房源编号已经被占用,请重新输入房源编号!更多帮助信息请使用参数'help'!")

case 3:
fmt.Println("您要查找的房源信息不存在,请验证房源编号准确性后再试!更多帮助信息请使用参数'help'!")

case 4:
fmt.Println("您要删除的房源数据不存在,请验证房源编号准确性后再试!更多帮助信息请使用参数'help'!")

default:
fmt.Println("未知错误!更多帮助信息请使用参数'help'!")
}
}

func houseCounts(houses map[string]house) {
line()
fmt.Println("【房源数量】您已进入房源数量统计模式")
counts := len(houses)
fmt.Printf("当前已经录入了 %d 套房源信息!", counts)
line()

}

func deleteHouse(houses map[string]house) {
line()
fmt.Println("【删除数据】您已进入房源数据删除模式")
var exists bool
for {
fmt.Println("请输入你要删除的房源编号")
fmt.Scan(&houseCode,)
_, exists = houses[houseCode]
if !exists {
errorHappen(4)
continue
}
break
}
delete(houses, houseCode)
fmt.Printf("编号为%s的房源数据删除成功!", houseCode)

fmt.Println("成功退出房源删除模式,回到主程序!")
line()

}

func insertHouse(houses map[string]house) {
for {
line()
fmt.Println("【新增数据】您已进入新增房源数据模式:")
fmt.Println("1、请输入房源编号")
fmt.Scan(&houseCode,)

_, exit := houses[houseCode]
if exit {
errorHappen(2)
continue
}
break
}


fmt.Println("2、请输入房源价格(正整数,单位:元)")
fmt.Scan(&price,)
fmt.Println("3、请输入房源面积(保留1位小数,单位:平方米)")
fmt.Scan(&area,)

for {
fmt.Println("4、请输入房源是否为首次出租(是 否)")
fmt.Scan(&isNewName,)
if isNewName == "是" {
isNew = true
break
} else if isNewName == "否" {
isNew = false
break
} else {
errorHappen(1)
}
}
fmt.Println("5、请输入房源标签并用','隔开")
fmt.Scan(&tags,)


house := house{
houseCode,
price,
area,
isNew,
tags,
}

houses[house.houseCode] = house
fmt.Println("恭喜您!房源"+ house.houseCode +"的房源信息保存成功!")
fmt.Println("成功退出房源保存模式,回到主程序!")
line()

}

func readHouse(houses map[string]house) {
line()
fmt.Println("【查询数据】您已进入查询房源数据模式:")
var (
house house
exists bool
)
for {
fmt.Println("请输入你要查询的房源编号")
fmt.Scan(&houseCode,)
house, exists = houses[houseCode]
if !exists {
errorHappen(3)
continue
}
break
}

fmt.Println("已为您查询到该房源数据,具体房源信息如下:")
fmt.Println("【房源编号】" + house.houseCode)
fmt.Printf("【房源价格】%d 元/月\n", house.price)
fmt.Printf("【房源面积】 %f 平方米\n", house.area)
if house.isNew {
fmt.Println( "【首次出租】是")
} else {
fmt.Println( "【首次出租】否")
}

fmt.Println( "【房源标签】:" + house.tags)
fmt.Println("成功退出房源查询模式,回到主程序!")
line()


}



func main(){

const helpFlag = "help"
var action string



//定义map存储房源数据
houses := map[string]house{}

//进入主程序控制流程
fmt.Println("欢迎进入凯冰科技房源管理系统")
line()

for {
fmt.Println("当前可进行的操作如下,请输入对应的数字编号:")
menu()

fmt.Scan(&action,)

switch action {
case "1":
readHouse(houses)
continue

case "2":
insertHouse(houses)
continue

case "3":
deleteHouse(houses)
continue

case "4":
help()
continue

case "5":
houseCounts(houses)

case "6":
fmt.Println("您已成功退出程序运行!感谢您的使用!")
os.Exit(0)
default:
errorHappen(1)
}
}

}




















  查看全部
【Day4任务】
学习GO语言组织数据的容器:数组,切片,映射,列表以及结构体。
用学到的知识实现下面的题目:
设计一个程序,可以录入、读取和删除房源数据,房源数据包括房源名称,房源编号,房源价格(正整数),房源面积(浮点数),是否是首次出租(布尔类型),房源标签(新校区,进地铁,深呼吸,独立卫生间等不限)。
读取房源时通过房源编号读取信息。
打卡时间:2月24日(周日)23:30前
打卡形式:代码运行截图+代码源码
package main

import (
"fmt"
"os"

)

//定义房源结构体
type house struct {
houseCode string
price int
area float64
isNew bool
tags string
}

var (
houseCode string
price int
area float64
isNewName string
isNew bool
tags string
)

func help(){

fmt.Println("请按照提示信息录入房源数据,并根据房源编号显示房源数据:")

}

func line() {
fmt.Println("*********************************")

}

func menu() {
fmt.Println("*********************************")
fmt.Println("1、查询房源(Select)")
fmt.Println("2、新增房源(Insert)")
fmt.Println("3、删除房源(Delete)")
fmt.Println("4、帮助信息(Help)")
fmt.Println("5、统计房源数量(Counts)")
fmt.Println("6、退出程序(Exit)")
fmt.Println("*********************************")

}

func errorHappen(no int) {

switch no {

case 1:
fmt.Println("参数错误!更多帮助信息请使用参数'help'!")

case 2:
fmt.Println("该房源编号已经被占用,请重新输入房源编号!更多帮助信息请使用参数'help'!")

case 3:
fmt.Println("您要查找的房源信息不存在,请验证房源编号准确性后再试!更多帮助信息请使用参数'help'!")

case 4:
fmt.Println("您要删除的房源数据不存在,请验证房源编号准确性后再试!更多帮助信息请使用参数'help'!")

default:
fmt.Println("未知错误!更多帮助信息请使用参数'help'!")
}
}

func houseCounts(houses map[string]house) {
line()
fmt.Println("【房源数量】您已进入房源数量统计模式")
counts := len(houses)
fmt.Printf("当前已经录入了 %d 套房源信息!", counts)
line()

}

func deleteHouse(houses map[string]house) {
line()
fmt.Println("【删除数据】您已进入房源数据删除模式")
var exists bool
for {
fmt.Println("请输入你要删除的房源编号")
fmt.Scan(&houseCode,)
_, exists = houses[houseCode]
if !exists {
errorHappen(4)
continue
}
break
}
delete(houses, houseCode)
fmt.Printf("编号为%s的房源数据删除成功!", houseCode)

fmt.Println("成功退出房源删除模式,回到主程序!")
line()

}

func insertHouse(houses map[string]house) {
for {
line()
fmt.Println("【新增数据】您已进入新增房源数据模式:")
fmt.Println("1、请输入房源编号")
fmt.Scan(&houseCode,)

_, exit := houses[houseCode]
if exit {
errorHappen(2)
continue
}
break
}


fmt.Println("2、请输入房源价格(正整数,单位:元)")
fmt.Scan(&price,)
fmt.Println("3、请输入房源面积(保留1位小数,单位:平方米)")
fmt.Scan(&area,)

for {
fmt.Println("4、请输入房源是否为首次出租(是 否)")
fmt.Scan(&isNewName,)
if isNewName == "是" {
isNew = true
break
} else if isNewName == "否" {
isNew = false
break
} else {
errorHappen(1)
}
}
fmt.Println("5、请输入房源标签并用','隔开")
fmt.Scan(&tags,)


house := house{
houseCode,
price,
area,
isNew,
tags,
}

houses[house.houseCode] = house
fmt.Println("恭喜您!房源"+ house.houseCode +"的房源信息保存成功!")
fmt.Println("成功退出房源保存模式,回到主程序!")
line()

}

func readHouse(houses map[string]house) {
line()
fmt.Println("【查询数据】您已进入查询房源数据模式:")
var (
house house
exists bool
)
for {
fmt.Println("请输入你要查询的房源编号")
fmt.Scan(&houseCode,)
house, exists = houses[houseCode]
if !exists {
errorHappen(3)
continue
}
break
}

fmt.Println("已为您查询到该房源数据,具体房源信息如下:")
fmt.Println("【房源编号】" + house.houseCode)
fmt.Printf("【房源价格】%d 元/月\n", house.price)
fmt.Printf("【房源面积】 %f 平方米\n", house.area)
if house.isNew {
fmt.Println( "【首次出租】是")
} else {
fmt.Println( "【首次出租】否")
}

fmt.Println( "【房源标签】:" + house.tags)
fmt.Println("成功退出房源查询模式,回到主程序!")
line()


}



func main(){

const helpFlag = "help"
var action string



//定义map存储房源数据
houses := map[string]house{}

//进入主程序控制流程
fmt.Println("欢迎进入凯冰科技房源管理系统")
line()

for {
fmt.Println("当前可进行的操作如下,请输入对应的数字编号:")
menu()

fmt.Scan(&action,)

switch action {
case "1":
readHouse(houses)
continue

case "2":
insertHouse(houses)
continue

case "3":
deleteHouse(houses)
continue

case "4":
help()
continue

case "5":
houseCounts(houses)

case "6":
fmt.Println("您已成功退出程序运行!感谢您的使用!")
os.Exit(0)
default:
errorHappen(1)
}
}

}

微信图片_20190225101127.png


微信图片_20190225101132.png


微信图片_20190225101137.png


微信图片_20190225101147.png

 

#自学课程#《放学你别走第一季之GO语言学习》Day3打卡

GoLangzkbhj 发表了文章 • 0 个评论 • 118 次浏览 • 2019-02-25 10:11 • 来自相关话题

【Day3任务】
学习GO语言的流程控制和函数。
用学到的知识实现下面的题目:
要求用户输入一个年份和一个月份,判断(要求使用嵌套的if…else和switch分别判断一次)该年该月有多少天。
打卡时间:2月23日(周六)23:30前
打卡形式:代码运行截图+代码源码
package main

import (
"fmt"
"strconv"
"os"
)

func help(){

fmt.Println("请依次按顺序输入年份和月份2个参数,用空格隔开,例如要查看2019年2月的天数,请输入:2019 2")

}

func errorHappen(no int) {

switch no {

case 1:
fmt.Println("参数错误!更多帮助信息请使用参数'help'!")

case 2:
fmt.Println("月份为大于0小于13的正整数,您输入的月份不合法!更多帮助信息请使用参数'help'!")

case 3:
fmt.Println("年份为大于0的正整数,您输入的年份不合法!更多帮助信息请使用参数'help'!")

default:
fmt.Println("未知错误!更多帮助信息请使用参数'help'!")
}
}

func isLeap(year int) int {

isLeap := 0
if year % 4 == 0 && year % 100 != 0 {
isLeap = 1
}

return isLeap

}

func main(){

const helpFlag = "help"


args := os.Args

//输入帮助符号
if len(args) == 2 && helpFlag == args[1] {
help()
os.Exit(0)
}

//判断参数传递是否正确
if len(args) < 2 || args == nil {
errorHappen(1)
os.Exit(0)

}




//获取数据
year, _ := strconv.Atoi(args[1])
month := args[2]
days := 0

//判断月份合法
m,_ := strconv.Atoi(args[2])
if m < 0 || m >12{
errorHappen(2)
os.Exit(0)
}


//判断年份合法
if year < 0 {
errorHappen(3)
os.Exit(0)
}

//使用switch case 实现流程控制
switch month {

case "1","3","5","7","8","10","12":{
days = 31

}

case "4","6","9","11":{
days = 30
}

case "2" : {
if 1 == isLeap(year) {
days = 29
}else{
days = 28
}

}

default:
help()

}

//打印结果
fmt.Printf("%d年%s月一共有%d天!",year,month,days)

}





  查看全部
【Day3任务】
学习GO语言的流程控制和函数。
用学到的知识实现下面的题目:
要求用户输入一个年份和一个月份,判断(要求使用嵌套的if…else和switch分别判断一次)该年该月有多少天。
打卡时间:2月23日(周六)23:30前
打卡形式:代码运行截图+代码源码
package main

import (
"fmt"
"strconv"
"os"
)

func help(){

fmt.Println("请依次按顺序输入年份和月份2个参数,用空格隔开,例如要查看2019年2月的天数,请输入:2019 2")

}

func errorHappen(no int) {

switch no {

case 1:
fmt.Println("参数错误!更多帮助信息请使用参数'help'!")

case 2:
fmt.Println("月份为大于0小于13的正整数,您输入的月份不合法!更多帮助信息请使用参数'help'!")

case 3:
fmt.Println("年份为大于0的正整数,您输入的年份不合法!更多帮助信息请使用参数'help'!")

default:
fmt.Println("未知错误!更多帮助信息请使用参数'help'!")
}
}

func isLeap(year int) int {

isLeap := 0
if year % 4 == 0 && year % 100 != 0 {
isLeap = 1
}

return isLeap

}

func main(){

const helpFlag = "help"


args := os.Args

//输入帮助符号
if len(args) == 2 && helpFlag == args[1] {
help()
os.Exit(0)
}

//判断参数传递是否正确
if len(args) < 2 || args == nil {
errorHappen(1)
os.Exit(0)

}




//获取数据
year, _ := strconv.Atoi(args[1])
month := args[2]
days := 0

//判断月份合法
m,_ := strconv.Atoi(args[2])
if m < 0 || m >12{
errorHappen(2)
os.Exit(0)
}


//判断年份合法
if year < 0 {
errorHappen(3)
os.Exit(0)
}

//使用switch case 实现流程控制
switch month {

case "1","3","5","7","8","10","12":{
days = 31

}

case "4","6","9","11":{
days = 30
}

case "2" : {
if 1 == isLeap(year) {
days = 29
}else{
days = 28
}

}

default:
help()

}

//打印结果
fmt.Printf("%d年%s月一共有%d天!",year,month,days)

}

微信图片_20190225101021.png

 

常用的GO语言内部包解析

GoLangzkbhj 发表了文章 • 0 个评论 • 113 次浏览 • 2019-02-25 10:08 • 来自相关话题

一、Go 标准库可以大致按其中库的功能进行以下粗略的分类


输入输出:这个分类包括二进制以及文本格式在屏幕、键盘、文件以及其他设备上的输
入输出等,比如二进制文件的读写。对应于此分类的包有bufio、 fmt、 io、 log和flag
等,其中 flag 用于处理命令行参数。

文本处理:这个分类包括字符串和文本内容的处理,比如字符编码转换等。对应于此分
类的包有encoding、 bytes、 strings、 strconv、 text、 mime、 unicode、 regexp、
index和path等。其中path用于处理路径字符串。

网络:这个分类包括开发网络程序所需要的包,比如Socket编程和网站开发等。对应于此
分类的包有: net、 http和expvar等。

系统:这个分类包含对系统功能的封装,比如对操作系统的交互以及原子性操作等。对
应于此分类的包有os、 syscall、 sync、 time和unsafe等。

数据结构与算法:对应于此分类的包有math、 sort、 container、 crypto、 hash、
archive、 compress和image等。因为image包里提供的图像编解码都是算法,所以也
归入此类。

运行时:对应于此分类的包有: runtime、 reflect和go等。

 二、常用包介绍
这里介绍Go语言标准库里使用频率相对较高的一些包 (如下):
 
fmt。它实现了格式化的输入输出操作,其中的fmt.Printf()和fmt.Println()是开发者使用最为频繁的函数。io。它实现了一系列非平台相关的IO相关接口和实现,比如提供了对os中系统相关的IO功能的封装。我们在进行流式读写(比如读写文件)时,通常会用到该包。bufio。它在io的基础上提供了缓存功能。在具备了缓存功能后, bufio可以比较方便地提供ReadLine之类的操作。strconv。本包提供字符串与基本数据类型互转的能力。os。本包提供了对操作系统功能的非平台相关访问接口。接口为Unix风格。提供的功能包括文件操作、进程管理、信号和用户账号等。sync。它提供了基本的同步原语。在多个goroutine访问共享资源的时候,需要使用sync中提供的锁机制。flag。它提供命令行参数的规则定义和传入参数解析的功能。绝大部分的命令行程序都需要用到这个包。encoding/json。 JSON目前广泛用做网络程序中的通信格式。本包提供了对JSON的基本支持,比如从一个对象序列化为JSON字符串,或者从JSON字符串反序列化出一个具体的对象等。http。它是一个强大而易用的包,也是Golang语言是一门“互联网语言”的最好佐证。通过http包,只需要数行代码,即可实现一个爬虫或者一个Web服务器,这在传统语言中是无法想象的。
 
三、完整包列表













































 
  查看全部
一、Go 标准库可以大致按其中库的功能进行以下粗略的分类



输入输出:这个分类包括二进制以及文本格式在屏幕、键盘、文件以及其他设备上的输
入输出等,比如二进制文件的读写。对应于此分类的包有bufio、 fmt、 io、 log和flag
等,其中 flag 用于处理命令行参数。

文本处理:这个分类包括字符串和文本内容的处理,比如字符编码转换等。对应于此分
类的包有encoding、 bytes、 strings、 strconv、 text、 mime、 unicode、 regexp、
index和path等。其中path用于处理路径字符串。

网络:这个分类包括开发网络程序所需要的包,比如Socket编程和网站开发等。对应于此
分类的包有: net、 http和expvar等。

系统:这个分类包含对系统功能的封装,比如对操作系统的交互以及原子性操作等。对
应于此分类的包有os、 syscall、 sync、 time和unsafe等。

数据结构与算法:对应于此分类的包有math、 sort、 container、 crypto、 hash、
archive、 compress和image等。因为image包里提供的图像编解码都是算法,所以也
归入此类。

运行时:对应于此分类的包有: runtime、 reflect和go等。


 二、常用包介绍
这里介绍Go语言标准库里使用频率相对较高的一些包 (如下):
 
  1. fmt。它实现了格式化的输入输出操作,其中的fmt.Printf()和fmt.Println()是开发者使用最为频繁的函数。
  2. io。它实现了一系列非平台相关的IO相关接口和实现,比如提供了对os中系统相关的IO功能的封装。我们在进行流式读写(比如读写文件)时,通常会用到该包。
  3. bufio。它在io的基础上提供了缓存功能。在具备了缓存功能后, bufio可以比较方便地提供ReadLine之类的操作。
  4. strconv。本包提供字符串与基本数据类型互转的能力。
  5. os。本包提供了对操作系统功能的非平台相关访问接口。接口为Unix风格。提供的功能包括文件操作、进程管理、信号和用户账号等。
  6. sync。它提供了基本的同步原语。在多个goroutine访问共享资源的时候,需要使用sync中提供的锁机制。
  7. flag。它提供命令行参数的规则定义和传入参数解析的功能。绝大部分的命令行程序都需要用到这个包。
  8. encoding/json。 JSON目前广泛用做网络程序中的通信格式。本包提供了对JSON的基本支持,比如从一个对象序列化为JSON字符串,或者从JSON字符串反序列化出一个具体的对象等。
  9. http。它是一个强大而易用的包,也是Golang语言是一门“互联网语言”的最好佐证。通过http包,只需要数行代码,即可实现一个爬虫或者一个Web服务器,这在传统语言中是无法想象的。

 
三、完整包列表

20181122133038383.png


20181122133121371.png


20181122133138459.png


20181122133154889.png


20181122133210116.png


20181122133225130.png


20181122133237835.png


20181122133316248.png


20181122133339570.png

 
 

#自学课程#《放学你别走第一季之GO语言学习》Day2打卡

GoLangzkbhj 发表了文章 • 0 个评论 • 112 次浏览 • 2019-02-22 14:54 • 来自相关话题

【Day2任务】
学习GO语言的基础数据类型,命名,变量,常量,格式化输入输出,类型转换及别名;运算符。
用学到的知识实现下面的题目:
用Go语言实现一个计算器程序,实现两个操作数的加、减、乘、除四种基本类型的操作,并可以指定最终计算结果的数据类型。
打卡时间:后天(2月22日)18:30
打卡形式:代码运行截图+现场面对面讨论package main

import (
"fmt"
"strconv"
"os"
)

func help(){

fmt.Println("请依次按顺序输入运算方法(add,sub,mul,div),数字1,数字2这三个参数,用空格隔开")

}

func errorHappen(no int) {

switch no {

case 1:
fmt.Println("参数错误!更多帮助信息请使用参数'help'!")

case 2:
fmt.Println("除法计算时,除数不能为0!更多帮助信息请使用参数'help'!")

default:
fmt.Println("未知错误!更多帮助信息请使用参数'help'!")
}
}

func main(){

const HELP_FLAG = "help"
const PRECISION = 2


args := os.Args

//输入帮助符号
if len(args) == 2 && HELP_FLAG == args[1] {
help()
os.Exit(0)
}

//判断参数传递是否正确
if len(args) < 3 || args == nil {
errorHappen(1)
os.Exit(0)

}


//获取计算方法
operator := args[1]
result := 0.0

//使用switch case 实现流程控制
switch operator {

case "add":{

number1, error1 := strconv.ParseFloat(args[2], PRECISION)
number2, error2 := strconv.ParseFloat(args[3], PRECISION)

if error1 == nil && error2 == nil {
result = number1 + number2

}

}


case "sub":{

number1, error1 := strconv.ParseFloat(args[2], PRECISION)
number2, error2 := strconv.ParseFloat(args[3], PRECISION)

if error1 == nil && error2 == nil {
result = number1 - number2

}

}

case "mul":{

number1, error1 := strconv.ParseFloat(args[2], PRECISION)
number2, error2 := strconv.ParseFloat(args[3], PRECISION)

if error1 == nil && error2 == nil {
result = number1 * number2

}

}

case "div":{

//判断除数是否为0
if "0" == args[3] {
errorHappen(2)
os.Exit(0)
}

number1, error1 := strconv.ParseFloat(args[2], PRECISION)
number2, error2 := strconv.ParseFloat(args[3], PRECISION)

if error1 == nil && error2 == nil {
result = number1 / number2

}

}

default:
help()

}

//打印结果
fmt.Println("计算结果为:",result)

}





  查看全部
【Day2任务】
学习GO语言的基础数据类型,命名,变量,常量,格式化输入输出,类型转换及别名;运算符。
用学到的知识实现下面的题目:
用Go语言实现一个计算器程序,实现两个操作数的加、减、乘、除四种基本类型的操作,并可以指定最终计算结果的数据类型。
打卡时间:后天(2月22日)18:30
打卡形式:代码运行截图+现场面对面讨论
package main

import (
"fmt"
"strconv"
"os"
)

func help(){

fmt.Println("请依次按顺序输入运算方法(add,sub,mul,div),数字1,数字2这三个参数,用空格隔开")

}

func errorHappen(no int) {

switch no {

case 1:
fmt.Println("参数错误!更多帮助信息请使用参数'help'!")

case 2:
fmt.Println("除法计算时,除数不能为0!更多帮助信息请使用参数'help'!")

default:
fmt.Println("未知错误!更多帮助信息请使用参数'help'!")
}
}

func main(){

const HELP_FLAG = "help"
const PRECISION = 2


args := os.Args

//输入帮助符号
if len(args) == 2 && HELP_FLAG == args[1] {
help()
os.Exit(0)
}

//判断参数传递是否正确
if len(args) < 3 || args == nil {
errorHappen(1)
os.Exit(0)

}


//获取计算方法
operator := args[1]
result := 0.0

//使用switch case 实现流程控制
switch operator {

case "add":{

number1, error1 := strconv.ParseFloat(args[2], PRECISION)
number2, error2 := strconv.ParseFloat(args[3], PRECISION)

if error1 == nil && error2 == nil {
result = number1 + number2

}

}


case "sub":{

number1, error1 := strconv.ParseFloat(args[2], PRECISION)
number2, error2 := strconv.ParseFloat(args[3], PRECISION)

if error1 == nil && error2 == nil {
result = number1 - number2

}

}

case "mul":{

number1, error1 := strconv.ParseFloat(args[2], PRECISION)
number2, error2 := strconv.ParseFloat(args[3], PRECISION)

if error1 == nil && error2 == nil {
result = number1 * number2

}

}

case "div":{

//判断除数是否为0
if "0" == args[3] {
errorHappen(2)
os.Exit(0)
}

number1, error1 := strconv.ParseFloat(args[2], PRECISION)
number2, error2 := strconv.ParseFloat(args[3], PRECISION)

if error1 == nil && error2 == nil {
result = number1 / number2

}

}

default:
help()

}

//打印结果
fmt.Println("计算结果为:",result)

}

微信图片_20190222145306.png

 

#自学课程#《放学你别走第一季之GO语言学习》Day1打卡

GoLangzkbhj 发表了文章 • 0 个评论 • 102 次浏览 • 2019-02-22 14:53 • 来自相关话题

【Day1任务】
熟悉Go编程语言,搭建运行环境,选择适合自己的IDE,并写出自己的第一个GO程序(hello world!),并用命令形式成功运行。
打卡时间:明天(2月21日)18:30
打卡形式:程序运行截图+现场面对面讨论package main

import "fmt"

func main(){
fmt.Printf("%s\n","Hello wolrd!This is my first go program!I'm ZhengKai!")
} 查看全部
【Day1任务】
熟悉Go编程语言,搭建运行环境,选择适合自己的IDE,并写出自己的第一个GO程序(hello world!),并用命令形式成功运行。
打卡时间:明天(2月21日)18:30
打卡形式:程序运行截图+现场面对面讨论
package main

import "fmt"

func main(){
fmt.Printf("%s\n","Hello wolrd!This is my first go program!I'm ZhengKai!")
}

两种数据序列化方案性能对比:Msgpack和Json

专业名词zkbhj 发表了文章 • 0 个评论 • 343 次浏览 • 2019-01-23 11:00 • 来自相关话题

    MessagePack(简写msgpack)是一个高效的二进制序列化格式。它让你像JSON一样可以在各种语言之间交换数据。但是它比JSON更快、更小。小的整数会被编码成一个字节,短的字符串仅仅只需要比它的长度多一字节的大小。之前在lua脚本中使用过msgpack,因为有大量数据要入redis,而考虑到内存开销,使用了压缩比更大的msgpack。因为msgpack是一个二进制格式,所以没法像json后的字符串一样可直观地查看数据。
 
    msgpack的官网地址:http://pecl.php.net/package/msgpack 里面有各PHP版本windows下的dll扩展,也有源码包供linux下编译,所以像lua这样的脚本语言可以直接使用。msgpack和json_encode都是序列化存储数据,那么msgpack的效率与json的效率相比的话到底怎么样呢?看下面这个简单的对比程序:
//msgpack与json的性能对比
//1,数据拼凑
$data =array(
'youku' => '优酷视频', 'pptv' => 'PPTV', 'sohu' => '搜狐视频', 'qiyi' => '奇艺视频', 'letv' => '乐视视频',
'tencent' => '腾讯视频', 'sina' => '新浪视频', 'tudou' => '土豆视频', 'm1905' => '电影网', 'cntv' => 'CNTV',
);
$data = json_encode($data);
$newArr = array();
for($i = 1; $i<=500; $i++) //修改此处$i的最大值以控制数据的大小
{
$newArr [] =$data;
}

//数据大小对比
$msg_data = msgpack_pack($newArr);
echo "使用msgpack处理后大小:".strlen($msg_data);
$json_data = json_encode($newArr);
echo "<br>使用json处理后大小:".strlen($json_data);
echo "<br>msgpack处理后大小与json处理后大小比为1:".round((strlen($json_data)/strlen($msg_data)),2);

//计算1000次msgpack压缩用时
$time = microtime(true);
for($i = 1; $i<1000; $i++){
msgpack_pack($newArr);
}
echo '<br>1000次msgpack操作用时:'.(microtime(true)- $time);

//计算1000次json_encode压缩用时
$time1 = microtime(true);
for($i = 1; $i<1000; $i++){
json_encode($newArr);
}
echo '<br>1000次json_encode操作用时:'.(microtime(true)- $time1); 程序过程没什么可说的了,就是先拼凑了一个数组数据(用$i来控制它的大小)。然后对比对这个数组的处理用时,如果$i很小,假如为2,得到的结果如下:
使用msgpack处理后大小:609
使用json处理后大小:751
msgpack处理后大小与json处理后大小比为1:1.23
1000次msgpack操作用时:0.05400013923645
1000次json_encode操作用时:0.03600001335144 从上面的结果来看,msg_pack的效率根本不如json_encode的效率,只是msg_pack的压缩率大些而已。而当我把$i改大点,比如改到500后,结果就完全反转了:
使用msgpack处理后大小:152003
使用json处理后大小:187501
msgpack处理后大小与json处理后大小比为1:1.23
1000次msgpack操作用时:0.68599987030029
1000次json_encode操作用时:2.2000000476837     经过多次测试,最后做两个总结如下:    1,msg_pack的压缩效率比json_encode大是毫无疑问,但压缩比我这只看到提高了20%左右,可能和数据类型有关系,这个值只供参考。


    2,在数据量较小的情况下,msg_pack的效率不如json_encode.而在数据量较大时,msg_pack的效率就远大于json_encode。

    3,和数据序列化一样,对数据的反序列化上,也是数量量大时,msg_unpack的效率远大于json_decode.

    下面是进行反序列化时的结果:
1000次msgpack操作用时:0.80399990081787
1000次json_encode操作用时:2.6389999389648 查看全部
    MessagePack(简写msgpack)是一个高效的二进制序列化格式。它让你像JSON一样可以在各种语言之间交换数据。但是它比JSON更快、更小。小的整数会被编码成一个字节,短的字符串仅仅只需要比它的长度多一字节的大小。之前在lua脚本中使用过msgpack,因为有大量数据要入redis,而考虑到内存开销,使用了压缩比更大的msgpack。因为msgpack是一个二进制格式,所以没法像json后的字符串一样可直观地查看数据。
 
    msgpack的官网地址:http://pecl.php.net/package/msgpack 里面有各PHP版本windows下的dll扩展,也有源码包供linux下编译,所以像lua这样的脚本语言可以直接使用。msgpack和json_encode都是序列化存储数据,那么msgpack的效率与json的效率相比的话到底怎么样呢?看下面这个简单的对比程序:
//msgpack与json的性能对比
//1,数据拼凑
$data =array(
'youku' => '优酷视频', 'pptv' => 'PPTV', 'sohu' => '搜狐视频', 'qiyi' => '奇艺视频', 'letv' => '乐视视频',
'tencent' => '腾讯视频', 'sina' => '新浪视频', 'tudou' => '土豆视频', 'm1905' => '电影网', 'cntv' => 'CNTV',
);
$data = json_encode($data);
$newArr = array();
for($i = 1; $i<=500; $i++) //修改此处$i的最大值以控制数据的大小
{
$newArr [] =$data;
}

//数据大小对比
$msg_data = msgpack_pack($newArr);
echo "使用msgpack处理后大小:".strlen($msg_data);
$json_data = json_encode($newArr);
echo "<br>使用json处理后大小:".strlen($json_data);
echo "<br>msgpack处理后大小与json处理后大小比为1:".round((strlen($json_data)/strlen($msg_data)),2);

//计算1000次msgpack压缩用时
$time = microtime(true);
for($i = 1; $i<1000; $i++){
msgpack_pack($newArr);
}
echo '<br>1000次msgpack操作用时:'.(microtime(true)- $time);

//计算1000次json_encode压缩用时
$time1 = microtime(true);
for($i = 1; $i<1000; $i++){
json_encode($newArr);
}
echo '<br>1000次json_encode操作用时:'.(microtime(true)- $time1);
 程序过程没什么可说的了,就是先拼凑了一个数组数据(用$i来控制它的大小)。然后对比对这个数组的处理用时,如果$i很小,假如为2,得到的结果如下:
使用msgpack处理后大小:609
使用json处理后大小:751
msgpack处理后大小与json处理后大小比为1:1.23
1000次msgpack操作用时:0.05400013923645
1000次json_encode操作用时:0.03600001335144
 从上面的结果来看,msg_pack的效率根本不如json_encode的效率,只是msg_pack的压缩率大些而已。而当我把$i改大点,比如改到500后,结果就完全反转了:
使用msgpack处理后大小:152003
使用json处理后大小:187501
msgpack处理后大小与json处理后大小比为1:1.23
1000次msgpack操作用时:0.68599987030029
1000次json_encode操作用时:2.2000000476837
     经过多次测试,最后做两个总结如下:    1,msg_pack的压缩效率比json_encode大是毫无疑问,但压缩比我这只看到提高了20%左右,可能和数据类型有关系,这个值只供参考。


    2,在数据量较小的情况下,msg_pack的效率不如json_encode.而在数据量较大时,msg_pack的效率就远大于json_encode。

    3,和数据序列化一样,对数据的反序列化上,也是数量量大时,msg_unpack的效率远大于json_decode.

    下面是进行反序列化时的结果:
1000次msgpack操作用时:0.80399990081787
1000次json_encode操作用时:2.6389999389648

服务保障经验谈之服务熔断

架构思想zkbhj 发表了文章 • 0 个评论 • 145 次浏览 • 2018-12-18 10:56 • 来自相关话题

什么是服务熔断?

熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。

这种牺牲局部,保全整体的措施就叫做熔断。

如果不采取熔断措施,我们的系统会怎样呢?我们来看一个栗子。

当前系统中有A,B,C三个服务,服务A是上游,服务B是中游,服务C是下游。它们的调用链如下:





 
一旦下游服务C因某些原因变得不可用,积压了大量请求,服务B的请求线程也随之阻塞。线程资源逐渐耗尽,使得服务B也变得不可用。紧接着,服务A也变为不可用,整个调用链路被拖垮。




像这种调用链路的连锁故障,叫做雪崩。

正所谓刮骨疗毒,壮士断腕。在这种时候,就需要我们的熔断机制来挽救整个系统。熔断机制的大体流程和刚才所讲的考试策略如出一辙:





 
这里需要解释两点:

1.开启熔断

在固定时间窗口内,接口调用超时比率达到一个阈值,会开启熔断。进入熔断状态后,后续对该服务接口的调用不再经过网络,直接执行本地的默认方法,达到服务降级的效果。


2.熔断回复

熔断不可能是永久的。当经过了规定时间之后,服务将从熔断状态回复过来,再次接受调用方的远程调用。
 
更多服务降级熔断限流,参考:https://www.cnblogs.com/raosha ... .html 查看全部
什么是服务熔断?

熔断这一概念来源于电子工程中的断路器(Circuit Breaker)。在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。

这种牺牲局部,保全整体的措施就叫做熔断。

如果不采取熔断措施,我们的系统会怎样呢?我们来看一个栗子。

当前系统中有A,B,C三个服务,服务A是上游,服务B是中游,服务C是下游。它们的调用链如下:

20180507103456708.png

 
一旦下游服务C因某些原因变得不可用,积压了大量请求,服务B的请求线程也随之阻塞。线程资源逐渐耗尽,使得服务B也变得不可用。紧接着,服务A也变为不可用,整个调用链路被拖垮。
20180507103502138.png

像这种调用链路的连锁故障,叫做雪崩

正所谓刮骨疗毒,壮士断腕。在这种时候,就需要我们的熔断机制来挽救整个系统。熔断机制的大体流程和刚才所讲的考试策略如出一辙:

20180507103507143.png

 
这里需要解释两点:

1.开启熔断

在固定时间窗口内,接口调用超时比率达到一个阈值,会开启熔断。进入熔断状态后,后续对该服务接口的调用不再经过网络,直接执行本地的默认方法,达到服务降级的效果。


2.熔断回复

熔断不可能是永久的。当经过了规定时间之后,服务将从熔断状态回复过来,再次接受调用方的远程调用。
 
更多服务降级熔断限流,参考:https://www.cnblogs.com/raosha ... .html

一点点学习Linux:如何添加crontab计划任务?

服务器zkbhj 发表了文章 • 0 个评论 • 169 次浏览 • 2018-11-13 11:53 • 来自相关话题

crond 是linux用来定期执行程序的命令。当安装完成操作系统之后,默认便会启动此任务调度命令。crond命令每分锺会定期检查是否有要执行的工作,如果有要执行的工作便会自动执行该工作。可以用以下的方法启动、关闭这个服务:
/sbin/service crond start //启动服务

/sbin/service crond stop //关闭服务

/sbin/service crond restart //重启服务

/sbin/service crond reload //重新载入配置1.linux任务调度的工作主要分为以下两类:

系统执行的工作:系统周期性所要执行的工作,如备份系统数据、清理缓存

个人执行的工作:某个用户定期要做的工作,例如每隔10分钟检查邮件服务器是否有新信,这些工作可由每个用户自行设置。


2.crontab命令选项:

cron服务提供crontab命令来设定cron服务的,以下是这个命令的一些参数与说明:

crontab -u //设定某个用户的cron服务,一般root用户在执行这个命令的时候需要此参数

crontab -l //列出某个用户cron服务的详细内容

crontab -r //删除某个用户的cron服务

crontab -e //编辑某个用户的cron服务

比如说root查看自己的cron设置:crontab -u root -l

再例如,root想删除fred的cron设置:crontab -u fred -r

在编辑cron服务时,编辑的内容有一些格式和约定,输入:crontab -u root -e

进入vi编辑模式,编辑的内容一定要符合下面的格式:*/1 * * * * ls >> /tmp/ls.txt

3.cron文件语法 分 小时 日 月 星期 命令

0-59 0-23 1-31 1-12 0-6 command (取值范围,0表示周日一般一行对应一个任务)4.记住几个特殊符号的含义:

"*"代表取值范围内的数字,

"/"代表"每",

"-"代表从某个数字到某个数字,

","分开几个离散的数字
 
5.举几个例子
5 * * * * ls //指定每小时的第5分钟执行一次ls命令

30 5 * * * ls //指定每天的 5:30 执行ls命令

30 7 8 * * ls //指定每月8号的7:30分执行ls命令

30 5 8 6 * ls //指定每年的6月8日5:30执行ls命令

30 6 * * 0 ls //指定每星期日的6:30执行ls命令[注:0表示星期天,1表示星期1,以此类推,也可以用英文来表示,sun表示星期天,mon表示星期一等。]

30 3 10,20 * * ls //每月10号及20号的3:30执行ls命令[注:”,”用来连接多个不连续的时段]

25 8-11 * * * ls //每天8-11点的第25分钟执行ls命令[注:”-”用来连接连续的时段]

*/15 * * * * ls //每15分钟执行一次ls命令 [即每个小时的第0 15 30 45 60分钟执行ls命令 ]

30 6 */10 * * ls //每个月中,每隔10天6:30执行一次ls命令[即每月的1、11、21、31日是的6:30执行一次ls命令。 ]

50 7 * * * root run-parts /etc/cron.daily //每天7:50以root 身份执行/etc/cron.daily目录中的所有可执行文件[ 注:run-parts参数表示,执行后面目录中的所有可执行文件。 ]6.新增调度任务可用两种方法:

a.在命令行输入: crontab -e 然后添加相应的任务,wq存盘退出。

b.直接编辑/etc/crontab 文件,即vi /etc/crontab,添加相应的任务。 查看全部
crond 是linux用来定期执行程序的命令。当安装完成操作系统之后,默认便会启动此任务调度命令。crond命令每分锺会定期检查是否有要执行的工作,如果有要执行的工作便会自动执行该工作。可以用以下的方法启动、关闭这个服务:
/sbin/service crond start //启动服务

/sbin/service crond stop //关闭服务

/sbin/service crond restart //重启服务

/sbin/service crond reload //重新载入配置
1.linux任务调度的工作主要分为以下两类:


系统执行的工作:系统周期性所要执行的工作,如备份系统数据、清理缓存

个人执行的工作:某个用户定期要做的工作,例如每隔10分钟检查邮件服务器是否有新信,这些工作可由每个用户自行设置。



2.crontab命令选项:

cron服务提供crontab命令来设定cron服务的,以下是这个命令的一些参数与说明:

crontab -u //设定某个用户的cron服务,一般root用户在执行这个命令的时候需要此参数

crontab -l //列出某个用户cron服务的详细内容

crontab -r //删除某个用户的cron服务

crontab -e //编辑某个用户的cron服务

比如说root查看自己的cron设置:crontab -u root -l

再例如,root想删除fred的cron设置:crontab -u fred -r

在编辑cron服务时,编辑的内容有一些格式和约定,输入:crontab -u root -e

进入vi编辑模式,编辑的内容一定要符合下面的格式:*/1 * * * * ls >> /tmp/ls.txt

3.cron文件语法
  分     小时      日       月       星期      命令

0-59 0-23 1-31 1-12 0-6 command (取值范围,0表示周日一般一行对应一个任务)
4.记住几个特殊符号的含义:

"*"代表取值范围内的数字,

"/"代表"每",

"-"代表从某个数字到某个数字,

","分开几个离散的数字
 
5.举几个例子
5       *       *       *      *     ls              //指定每小时的第5分钟执行一次ls命令

30 5 * * * ls //指定每天的 5:30 执行ls命令

30 7 8 * * ls //指定每月8号的7:30分执行ls命令

30 5 8 6 * ls //指定每年的6月8日5:30执行ls命令

30 6 * * 0 ls //指定每星期日的6:30执行ls命令[注:0表示星期天,1表示星期1,以此类推,也可以用英文来表示,sun表示星期天,mon表示星期一等。]

30 3 10,20 * * ls //每月10号及20号的3:30执行ls命令[注:”,”用来连接多个不连续的时段]

25 8-11 * * * ls //每天8-11点的第25分钟执行ls命令[注:”-”用来连接连续的时段]

*/15 * * * * ls //每15分钟执行一次ls命令 [即每个小时的第0 15 30 45 60分钟执行ls命令 ]

30 6 */10 * * ls //每个月中,每隔10天6:30执行一次ls命令[即每月的1、11、21、31日是的6:30执行一次ls命令。 ]

50 7 * * * root run-parts /etc/cron.daily //每天7:50以root 身份执行/etc/cron.daily目录中的所有可执行文件[ 注:run-parts参数表示,执行后面目录中的所有可执行文件。 ]
6.新增调度任务可用两种方法:

a.在命令行输入: crontab -e 然后添加相应的任务,wq存盘退出。

b.直接编辑/etc/crontab 文件,即vi /etc/crontab,添加相应的任务。

类设计的六大基本原则

架构思想zkbhj 发表了文章 • 0 个评论 • 155 次浏览 • 2018-11-12 20:12 • 来自相关话题

一.单一职责原则

Single Responsibility Principle, 简称SRP。

定义:There should never be more than one reason for a class to change.

应该有且仅有一个原因引起类的变更。
 
二.里氏替换原则

Liskov Substitution Principle, 简称LSP。

定义:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

(所有引用基类的地方必须能透明地使用其子类的对象)
 
三.依赖倒置原则

Dependence Inversion Principle, 简称DIP

定义:High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.

翻译过来,包含三层含义:

1.高层模块不应该依赖低层模块,两者都应该依赖其抽象。2.抽象不应该依赖细节。3.细节应该依赖抽象。

精简的定义: 面向接口编程。
 
四.接口隔离原则:
接口--这里指用interface关键字定义的接口。
定义:
1.Clients should not be forced to depend upon interfaces that they don't use.(客户端不应该依赖它不需要的接口)
2.The dependency of one class to anther one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上)

概括:建立单一接口,不要建立臃肿庞大的接口。通俗来讲:接口尽量细化,同时接口中的方法尽量少。
 
五.迪米特法则
Law of Demeter, LOD。又称最少知识原则(Least Knowledge Principle, LKP)。
通俗来讲:一个类应该对自己需要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没有关系,那是你的事情,我就调用你提供的public方法,其他一概不关心。
 
六.开闭原则
Software entities like classes, modules and functions should be open for extension but closed for modifications.(一个软件实体如类、模块和函数应该对扩展开放,对修改关闭) 查看全部
一.单一职责原则

Single Responsibility Principle, 简称SRP。

定义:There should never be more than one reason for a class to change.

应该有且仅有一个原因引起类的变更。
 
二.里氏替换原则

Liskov Substitution Principle, 简称LSP。

定义:Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

(所有引用基类的地方必须能透明地使用其子类的对象)
 
三.依赖倒置原则

Dependence Inversion Principle, 简称DIP

定义:High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.

翻译过来,包含三层含义:

1.高层模块不应该依赖低层模块,两者都应该依赖其抽象。2.抽象不应该依赖细节。3.细节应该依赖抽象。

精简的定义: 面向接口编程。
 
四.接口隔离原则:
接口--这里指用interface关键字定义的接口。
定义:
1.Clients should not be forced to depend upon interfaces that they don't use.(客户端不应该依赖它不需要的接口)
2.The dependency of one class to anther one should depend on the smallest possible interface.(类间的依赖关系应该建立在最小的接口上)

概括:建立单一接口,不要建立臃肿庞大的接口。通俗来讲:接口尽量细化,同时接口中的方法尽量少。
 
五.迪米特法则
Law of Demeter, LOD。又称最少知识原则(Least Knowledge Principle, LKP)。
通俗来讲:一个类应该对自己需要耦合或调用的类知道得最少,你(被耦合或调用的类)的内部是如何复杂都和我没有关系,那是你的事情,我就调用你提供的public方法,其他一概不关心。
 
六.开闭原则
Software entities like classes, modules and functions should be open for extension but closed for modifications.(一个软件实体如类、模块和函数应该对扩展开放,对修改关闭)