Spiga

Go学习笔记(三):接口

2020-04-12 14:38:51

摘要:封装数据与行为 结构体定义 type Employee struct { Id string Name string Age int } 实例创建及初始化 e := Employee{0, Bob, 20} e1 := Employee{Name: Mike, Age: 30} e2 := new(Employee) //注意这⾥返回的引⽤/指针,相当于 e := Employee{} e2.Id = “2 //与其他主要编程语⾔的差异:通过实例的指针访问成员不需要使⽤- e2.Age = 22 e2.Name = “Rose 行为(方法)定义 //第⼀种定义⽅式在实例对应⽅法被调⽤时,实例的成员会进⾏值复制 func (e Employee) String() string { return fmt.Sprintf(ID:%s-Name:%s-Age:%d, e.Id, e.Name, e.Age) } //通常情况下为了避免内存拷⻉我们使⽤第⼆种定义⽅式 func (e *Employee) String() string { return fmt.Sprintf(ID:%s/Name:%s/Age:%d, e.Id, e.Name, e.Age) } type Employee struct { Id string Name string Age int } func (e Employee) String() string { //这里传递的是类型 fmt.Printf(Address is %x, unsafe.Pointer(e.Name)) } func TestStructOperations(t *testing.T) { e := Employee{0, Bob, 20} fmt.Printf(Address is %x, unsafe.Pointer(e.Name)) t.Log(e.String()) //Address is c000068520 Address is c000068550 } 可以看到上面测试程序调用String方法时传递的是类型,log得到的是2不同的地址,如果改成传递地址呢? func (e Employee) String() …… 阅读全文

Go学习笔记(二):语法基础2

2020-04-09 13:17:12

摘要:数组 数组的声明 var a [3]int //声明并初始化为默认零值 a[0] = 1 b := [3]int{1,2,3} c := [...]int{1,2,3,4,5} //不指定元素个数 d := [2][2]int{{1,2},{3,4}} //多维数组初始化 数组元素遍历 func TestTravelArray(t testing.T) { a := [...]{1,2,3,4,5} for idx/*索引*/,elem/*元素*/ := range a { fmt.PrintIn(idx, elem) } } 数组截取 a[开始索引(包含),结束索引(不报销)] a := [...]int{1,2,3,4,5} a[1:2] //2 a[1:3] //2,3 a[1:len(a)] //2,3,4,5 a[1:] //2,3,4,5 a[:3] //1,2,3 切片 切片的声明 var s0 []int s0 = append(s0, 1) s := []int{} s1 := []int{1, 2, 3} s2 := make([]int, 2, 4) /* []type, len, cap 其中len个元素会被初始化为默认零值,未初始化元素不可以访问 */ 切片共享存储结构 func TestSliceShareMemory(t *testing.T) { year := []string{Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec} Q2 := year[3:6] t.Log(Q2, len(Q2), cap(Q2)) //3,9 summer := year[5:8] t.Log(summer, len(summer), cap(summer)) //3,7 summer[0] = Unknow t.Log(Q2) //因为是共享存储,上一句修改summer[0]会影响Q2的值,结果 [Apr,May,Unknow] t.Log(year) //同理year也会受到summer的赋值影响 }…… 阅读全文

Go学习笔记(一):语法基础1

2020-04-08 11:50:28

摘要:1.编写第一个Go程序 首先我们编写一个Hello World程序 package main //包,表明代码所在的模块(包) import fmt //引⼊代码依赖 //功能实现 func main() { fmt.Println(Hello World!) } 应用程序入口 1.必须是 main 包:package main 2.必须是 main ⽅法:func main() 3.⽂件名不⼀定是main.go main函数的返回值和参数 与其他主要编程语⾔的差异 Go 中main函数不⽀持任何返回值 需要通过os.Exit来返回状态 同样main 函数不⽀持传⼊参数 func main(arg []string) 在程序中直接通过os.Args获取命令⾏参数 package main import ( fmt os ) func main() { if len(os.Args) 1 { fmt.Println(Hello World, os.Args[1]) } os.Exit(-1) } 2. 变量与常量 在开始前先介绍一下go语言如何编写一个测试代码,方便编写测试程序。go语言只要满足下面2点规则就能运行测试 源码⽂件以_test结尾:xxx_test.go 测试⽅法名以Test开头:func TestXXX(t *testing.T) {…} 接下来我们编写一个Fibonacci 数列来介绍变量的定义 数列:1, 1, 2, 3, 5, 8, 13, …. import ( testing ) func TestFibList(t *testing.T) {    // 1. 变量声明一般方法 // var a int = 1 // var b int = 1        // 2. 统一一起声明,注意变量b 去掉了类型定义,系统可以根据赋值自动判断 // var ( // a int = 1 // b     = 1 // )        // 3. 方法3,快捷声明与赋值(推荐) a := 1 b := 1 t.Log(a) for i := 0; i 5…… 阅读全文

数据库调优

2019-11-16 15:35:24

摘要:影响性能因素 数据库结构设计 T-SQL语句 数据量大 事务和隔离级别 硬件资源 IO阻塞 批量删除表数据:大量删除时会记录到日志中,也会造成IO阻塞 优化和注意事项 了解业务 优先考虑第三范式设计,参考设计范式 表关联尽可能少 坚持最小原则 在适当的地方使用约束 用户数据和日志文件隔离存放 T-SQL语句优化 使用字段名,尽量不适用* 条件 从左边开始,先写最小条件锁定最少数据 索引 尽量使用索引字段 索引字段放到左边 不能计算也不要使用函数,否则索引失效 以小表关联大表 SQL语句尽量简单 执行计划 sql官方执行计划文档 执行计划图标和运算符 MSSQLSERVER执行计划详解 - 张龙豪 - 博客园 SQL Server执行计划的理解 - 馨馨妙 - 博客园 点击开启【包括实际的执行计划】 执行计划关键字和图标理解 表扫描: Parameter Table Scan 运算符扫描在当前查询中用作参数的表。 该运算符一般用于存储过程内的 INSERT 查询。 Parameter Table Scan 既是一个逻辑运算符,也是一个物理运算符。 就是扫描查询列整个表全部数据,最耗时性能最低的。 嵌套循环: Nested Loops 运算符执行内部联接、左外部联接、左半部联接和左反半部联接逻辑运算。 嵌套循环联接通常使用索引,针对外部表的每一行在内部表中执行搜索。 查询处理器根据预计的开销来决定是否对外部输入进行排序,以改进内部输入索引上的搜索定位。 将基于所执行的逻辑操作返回所有满足 Argument 列中的(可选)谓词的行。 如果 OPTIMIZED 特性设置为“True”,则表示使用了优化的嵌套循环(或批处理排序) 。 Nested Loops 是一个物理运算符。 有关详细信息,请参阅了解嵌套循环联接。 RID查询 : RID Lookup 是使用提供的行标识符 (RID) 在堆上进行的书签查找。 Argument 列包含用于查找表中的行的书签标签和从中查找行的表的名称。 RID Lookup 通常带有 NESTED LOOP JOIN。 RID Lookup 是一个物理运算符。 有关书签查找的详细信息,请参阅 MSDN SQL Server 博客中的Bookmark Lookup(书签查找)。 哈希匹配: Hash Ma…… 阅读全文

控制反转IOC+依赖注入DI

2019-11-13 23:06:01

摘要:参考 蒋金楠:书籍《ASP.NET Core 3框架揭秘》、博客园 :ASP.NET Core 3框架揭秘 官方文档:在 ASP.NET Core 依赖注入 在 ASP.NET Core 中将依赖项注入到控制器 学完这篇依赖注入,与面试官扯皮就没有问题了。 一个接口注入多次:【ASP.NET Core】依赖注入高级玩法——如何注入多个服务实现类 、在.NET Core中处理一个接口多个不同实现的依赖注入问题 spring依赖注入和控制反转的理解,写的太好了 ASP.NET Core应用的7种依赖注入方式 概念 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。 控制反转是一种思想,依赖注入是一种设计模式。 依赖抽象不依赖具体 谁控制谁,控制什么 传统程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。 为何是反转,哪些方面反转了 有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。 阅读全文

微软云平台Microsoft Azure

2019-09-13 17:27:26

摘要:持续集成、继续部署、继续交付 持续集成(Continuous integration) 是一种软件开发实践,即团队开发成员经常集成它们的工作, 通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。 每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。 持续部署(continuous deployment) 是通过自动化的构建、测试和部署循环来快速交付高质量的产品。 某种程度上代表了一个开发团队工程化的程度,毕竟快速运转的互联网公司人力成本会高于机器, 投资机器优化开发流程化相对也提高了人的效率,让 engineering productivity 最大化。 持续交付(英语:Continuous delivery,缩写为 CD) 是一种软件工程手法, 让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定、 持续的保持在随时可以释出的状况。它的目标在于让软件的建置、 测试与释出变得更快以及更频繁。这种方式可以减少软件开发的成本与时间,减少风险。 DevOps DevOps(Development和Operations的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。 它是一种重视“软件开发人员(Dev)”和“IT运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。透过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。 它的出现是由于软件行业日益清晰地认识到:为了按时交付软件产品和服务,开发和运维工作必须紧密合作。 Jenkins Jenkins是实现DevOps的工具 Jenkins是一款开源 CICD 软件,用于自动化各种任务,包括构建、测试和部署软件。 Jenkins 支持各种运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序。 特点: 易于安装,只要把jenkins.war部署到servlet容器 易于配置-所有配置都通过其提供的web界面实现。 集成RSS/E-mail通过RSS发布构建结果或当构件完成是通过e-mail通知。 生成JUnit/TestNG测试报告。 分布式构建支持Jenkins能够让多台计算机一起构建/测试。 文件识别:Jenkins能够跟…… 阅读全文

[推荐] EntityFrameworkCore

2019-07-24 19:56:36

摘要:执行sql 基于原始SQL查询创建LINQ查询,代替旧版的FromSql、SqlQuery 基本原生 SQL 查询 可使用 FromSqlRaw 扩展方法基于原始 SQL 查询开始 LINQ 查询。 FromSqlRaw 只能在直接位于 DbSet 上的查询根上使用 //在 SQL 查询字符串中包含形参占位符并提供额外的实参,将单个形参传递到存储过程 Blogs是Context上下文中配置的实体类属性 var user = johndoe; var blogs = context.Blogs.FromSqlRaw(EXECUTE dbo.GetMostPopularBlogsForUser {0}, user).ToList(); //使用字符串内插语法,该值会转换为 DbParameter,且不易受到 SQL 注入攻击 var user = johndoe; var blogs = context.Blogs.FromSqlInterpolated($EXECUTE dbo.GetMostPopularBlogsForUser {user}).ToList(); //DbParameter 并将其作为参数值提供。 由于使用了常规 SQL 参数占位符而不是字符串占位符,因此可安全地使用 FromSqlRaw var user = new SqlParameter(user, johndoe); var blogs = context.Blogs.FromSqlRaw(EXECUTE dbo.GetMostPopularBlogsForUser @user, user).ToList(); //借助 FromSqlRaw,可以在 SQL 查询字符串中使用已命名的参数,这在存储的流程具有可选参数时非常有用 var user = new SqlParameter(user, johndoe); var blogs = context.Blogs.FromSqlRaw(EXECUTE dbo.GetMostPopularBlogsForUser @filterByUser=@user, user).ToList(); Database.ExecuteSqlRaw 针对数据库执行给定的SQL,并返回受影响的行数,代替旧版的ExecuteSqlCommand…… 阅读全文

设计原则与思想(四):规范和重构

2019-05-26 18:36:57

摘要: 重构概述 重构的目的:为什么重构(why)? 对于项目来言,重构可以保持代码质量持续处于一个可控状态,不至于腐化到无可救药的地步。对于个人而言,重构非常锻炼一个人的代码能力,并且是一件非常有成就感的事情。它是我们学习的经典设计思想、原则、模式、编程规范等理论知识的练兵场。 重构的对象:重构什么(what)? 按照重构的规模,我们可以将重构大致分为大规模高层次的重构和小规模低层次的重构。大规模高层次重构包括对代码分层、模块化、解耦、梳理类之间的交互关系、抽象复用组件等等。这部分工作利用的更多的是比较抽象、比较顶层的设计思想、原则、模式。小规模低层次的重构包括规范命名、注释、修正函数参数过多、消除超大类、提取重复代码等等编程细节问题,主要是针对类、函数级别的重构。小规模低层次的重构更多的是利用编码规范这一理论知识。 重构的时机:什么时候重构(when)? 我们一定要建立持续重构意识,把重构作为开发必不可少的部分,融入到日常开发中,而不是等到代码出现很大问题的时候,再大刀阔斧地重构。 重构的方法:如何重构(how)? 大规模高层次的重构难度比较大,需要组织、有计划地进行,分阶段地小步快跑,时刻让代码处于一个可运行的状态。而小规模低层次的重构,因为影响范围小,改动耗时短,所以,只要你愿意并且有时间,随时随地都可以去做。 单元测试 什么是单元测试? 单元测试是代码层面的测试,由研发自己来编写,用于测试“自己”编写的代码的逻辑的正确性。单元测试顾名思义是测试一个“单元”,有别于集成测试,这个“单元”一般是类或函数,而不是模块或者系统。 为什么要写单元测试? 写单元测试的过程本身就是代码 Code Review 和重构的过程,能有效地发现代码中的 bug 和代码设计上的问题。除此之外,单元测试还是对集成测试的有力补充,还能帮助我们快速熟悉代码,是 TDD 可落地执行的改进方案。 如何编写单元测试? 写单元测试就是针对代码设计各种测试用例,以覆盖各种输入、异常、边界情况,并将其翻译成代码。我们可以利用一些测试框架来简化单元测试的编写。除此之外,对于单元测试,我们需要建立以下正确的认知: 编写单元测试尽管繁琐,但并不是太耗时; 我们可以稍微放低对单元测试代码质量的要求; 覆盖率作为衡量单元测试质量的唯一标准是不合理的; 单元测试不要依赖被测代码的具体实现逻辑…… 阅读全文

设计原则与思想(三):设计原则

2019-05-19 16:35:32

摘要: 经典的设计原则,其中包括,SOLID、KISS、YAGNI、DRY、LOD 等。SOLID 原则,实际上,SOLID 原则并非单纯的 1 个原则,而是由 5 个设计原则组成的,它们分别是:单一职责原则、开闭原则、里式替换原则、接口隔离原则和依赖反转原则,依次对应 SOLID 中的 S、O、L、I、D 这 5 个英文字母。 单一职责原则(SRP) 如何理解单一职责原则(SRP)? 一个类只负责完成一个职责或者功能。不要设计大而全的类,要设计粒度小、功能单一的类。单一职责原则是为了实现代码高内聚、低耦合,提高代码的复用性、可读性、可维护性。 如何判断类的职责是否足够单一? 不同的应用场景、不同阶段的需求背景、不同的业务层面,对同一个类的职责是否单一,可能会有不同的判定结果。实际上,一些侧面的判断指标更具有指导意义和可执行性,比如,出现下面这些情况就有可能说明这类的设计不满足单一职责原则:类中的代码行数、函数或者属性过多;类依赖的其他类过多,或者依赖类的其他类过多;私有方法过多;比较难给类起一个合适的名字;类中大量的方法都是集中操作类中的某几个属性。 类的职责是否设计得越单一越好? 单一职责原则通过避免设计大而全的类,避免将不相关的功能耦合在一起,来提高类的内聚性。同时,类职责单一,类依赖的和被依赖的其他类也会变少,减少了代码的耦合性,以此来实现代码的高内聚、低耦合。但是,如果拆分得过细,实际上会适得其反,反倒会降低内聚性,也会影响代码的可维护性。 出现下面这些情况就有可能说明这类的设计不满足单一职责原则: 类中的代码行数、函数或者属性过多; 类依赖的其他类过多或者依赖类的其他类过多; 私有方法过多; 比较难给类起一个合适的名字; 类中大量的方法都是集中操作类中的某几个属性。 开闭原则(OCP) 如何理解“对扩展开放、对修改关闭”? 添加一个新的功能,应该是通过在已有代码基础上扩展代码(新增模块、类、方法、属性等),而非修改已有代码(修改模块、类、方法、属性等)的方式来完成。关于定义,我们有两点要注意。第一点是,开闭原则并不是说完全杜绝修改,而是以最小的修改代码的代价来完成新功能的开发。第二点是,同样的代码改动,在粗代码粒度下,可能被认定为“修改”;在细代码粒度下,可能又被认定为“扩展”。 如何做到“对扩展开放、修改关闭”? 我们要时刻具备扩展意…… 阅读全文

设计原则与思想(二):面向对象

2019-05-12 10:35:23

摘要: 面向对象概述 什么是面向对象编程? 面向对象编程是一种编程范式或编程风格。它以类或对象作为组织代码的基本单元,并将封装、抽象、继承、多态四个特性,作为代码设计和实现的基石 。 什么是面向对象编程语言? 面向对象编程语言是支持类或对象的语法机制,并有现成的语法机制,能方便地实现面向对象编程四大特性(封装、抽象、继承、多态)的编程语言。 如何判定一个编程语言是否是面向对象编程语言? 如果按照严格的的定义,需要有现成的语法支持类、对象、四大特性才能叫作面向对象编程语言。如果放宽要求的话,只要某种编程语言支持类、对象语法机制,那基本上就可以说这种编程语言是面向对象编程语言了,不一定非得要求具有所有的四大特性。 面向对象编程和面向对象编程语言之间有何关系? 面向对象编程一般使用面向对象编程语言来进行,但是,不用面向对象编程语言,我们照样可以进行面向对象编程。反过来讲,即便我们使用面向对象编程语言,写出来的代码也不一定是面向对象编程风格的,也有可能是面向过程编程风格的。 什么是面向对象分析和面向对象设计? 简单点讲,面向对象分析就是要搞清楚做什么,面向对象设计就是要搞清楚怎么做。两个阶段最终的产出是类的设计,包括程序被拆解为哪些类,每个类有哪些属性方法、类与类之间如何交互等等。 面向对象四大特性 关于封装特性 封装也叫作信息隐藏或者数据访问保护。类通过暴露有限的访问接口,授权外部仅能通过类提供的方式来访问内部信息或者数据。它需要编程语言提供权限访问控制语法来支持,例如 C# 中的 private、protected、public 关键字。封装特性存在的意义,一方面是保护数据不被随意修改,提高代码的可维护性;另一方面是仅暴露有限的必要接口,提高类的易用性。 关于抽象特性 封装主要讲如何隐藏信息、保护数据,那抽象就是讲如何隐藏方法的具体实现,让使用者只需要关心方法提供了哪些功能,不需要知道这些功能是如何实现的。抽象可以通过接口类或者抽象类来实现,但也并不需要特殊的语法机制来支持。抽象存在的意义,一方面是提高代码的可扩展性、维护性,修改实现不需要改变定义,减少代码的改动范围;另一方面,它也是处理复杂系统的有效手段,能有效地过滤掉不必要关注的信息。 关于继承特性 继承是用来表示类之间的 is-a 关系,分为两种模式:单继承和多继承。单继承表示一个子类只继承一个…… 阅读全文