-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 159 KB
/
content.json
1
{"meta":{"title":"iLife's Blog","subtitle":"Free Your mind","description":"Think Difference","author":"xiao","url":"https://ilifexiao.github.io"},"pages":[{"title":"about","date":"2018-05-18T09:23:58.000Z","updated":"2018-05-18T15:59:08.000Z","comments":true,"path":"about/index.html","permalink":"https://ilifexiao.github.io/about/index.html","excerpt":"","text":"关于网站 用来记录和分享自己的学习、生活、思考"}],"posts":[{"title":"微信小程序开发总结","slug":"小程序开发/帐号管理开发总结","date":"2018-08-02T07:02:05.000Z","updated":"2018-08-04T11:49:07.000Z","comments":true,"path":"2018/08/02/小程序开发/帐号管理开发总结/","link":"","permalink":"https://ilifexiao.github.io/2018/08/02/小程序开发/帐号管理开发总结/","excerpt":"","text":"帐号管理小程序——开发总结 从零开始写小程序,项目地址:GItHub,博客地址 1. 开发前期想法:最初的想法是想做一个管理手机号码所绑定的APP,通过自动更换手机绑定的过程,减少换手机号码锁带来的迁移成本。打算通过爬虫区自动去尝试常用应用的帐号是否绑定该手机号码,但是这样的效率太差了,并且那些网站都有做相应的保护,难以完成。 后面了解到了中国移动,开发了一个名为移动认证的应用,正在减弱密码的使用,使用一个帐号九可以登录所有的应用,同样增加了用户的迁移成本。 后面呢,随着前端开发的火热,以及微信应用的爆发。了解和接触前端开发似乎成为一个开发者必不可少的能力,抱着多多接触新技术和增长能力的想法,打算开发一个微信小程序作为前端的入门。 互联网的发展,使我们增添了许多获取信息的渠道,同样使得网络安全以及帐号安全成为一个主要问题。纷繁复杂的应用,和许多密码,通过人工记忆许多无规则的密码显然是不够合理的。使用同一个密码容易使得帐号盗号撞库发生。 综上所述,开发一个以可以记录,保存,备份,加密的帐号管理软件成为了一个较好的方式。 参考:在得到想法以后,参考了几个同样具有帐号管理的微信小程序,作为出发点。 onepassword 密码箱 准备: UI设计,墨刀,软件使用流程设计 icon资源来自IconFont、壁纸资源 加密算法来自开源分享1、开源分享2、开源分享3 微信开发者工具 开发文档 前端知识 2. 开发过程2.1 框架使用的开发框架: 使用WEUI来制作UI界面 微信的Markdown解析wxParse 该程序是使用WEUI来制作,大大降低了UI开发的难度,通过参考WEUI的代码,搭建出小程序的基本界面 实现每一项功能,实现数据存储 挖掘小程序的API,实现更多的功能,同时不断提高用户的体验 重构应用 其他开发框架: zanui-weapp TouchUI,能实现一套代码开发微信小程序和HTML页面 微信小程序-腾讯云解决方案,简化了小程序后端开发的难度 MpVue,一款让小程序支持组件化开发的框架,通过预编译的手段让开发者可以选择自己喜欢的开发风格去开发小程序。框架的细节优化,Promise,Async Functions的引入都是为了能让开发小程序项目变得更加简单,高效。 Wepy,是一个使用 Vue.js 开发小程序的前端框架。框架基于 Vue.js 核心,mpvue 修改了 Vue.js 的 runtime 和 compiler 实现,使其可以运行在小程序环境中,从而为小程序开发引入了整套 Vue.js 开发体验。 开发框架总结:从前端发展出来的微信小程序框架,可以看出,构建一个程序的方法有很多,重要的你的想法和逻辑,一个好的框架和完善的文档,能够让你快速的完成开发过程。 到目前的移动端(iOS,Android)同样可以通过前端来构建,比如目前火热的Flutter,可以使用一套代码构建出安卓和iOS端的APP,大大地减少了开发的难度和成本。缺点在于无法做到原生端那么的流畅和精美。但对于简单的开发需求完全可以胜任。 比如Alibaba的Wexx,框架可以构建三端的应用(iOS,Android,WEB) 从前端、移动端、WEB端的各种生态系统里,相同的是业务逻辑和想法,不同的只是标准。正所谓天下合久必分,分久必合。一个良好的生态环境和强大的技术能够实现一统三端,为相同的目标实现三套不同的标准可谓是形态所迫,希望未来简单的编码过程交付于AI完全可以。你只要专注与业务设计和想法逻辑即可。 所以务实基础,才是构建大厦的根本,才能让你在不断变化的世界里游刃有余。 未来存在你与机器的区分之处,就是你的创造力和想象力。 2.2 逻辑&问题使用流程: 通过唯一的密码 或者 指纹登录验证后进入软件的主页面(数据存储、页面跳转、验证逻辑、页面布局) 主页显示基础的帐号分类,提供全局搜索的功能(数据预先加载&分类、控件重叠居中等) 点击分类显示帐号(同时在标题栏显示帐号的数量、右下角可以方便地添加帐号) 点击帐号(显示帐号的具体信息、页面的复用&传值、分享帐号) 点击设置(帐号导出&导入,导出的信息通过AES加密、修改密码&密钥、常见问题解答、用户帮助等) 开发逻辑:1. 验证页面用户打开程序,首先加载的是名为index的页面,所以需要设计验证页面为index,验证通过才能跳转到主页面。 在此之前需要判断用户是否第一次使用该软件(通过是否获取到登录密码为准,因为程序必要要用登录密码才能使用),第一次使用则需要设置密码。 获取密码通过程序的入口app.js来设置,并保存到全局变量APP中的globalData,通过getApp()来获取APP全局变量,这个同时也是页面传值的通道。 用到了wx.getStorageSync(key) || wx.getStorageAsync(key),需要注意避免获取为空的异常。 12345// 获取加密信息, 虽然是一个字典,但是数据是空的,自然旧获取不到keyvar secret = wx.getStorageSync('secret') || { \"key\": \"\", \"iv\": \"\"} 优化点1:这里使用了大量的同步API来获取缓存中的数据(主要是帐号),是导致程序启动缓慢的主要原因,可以考虑懒加载来提高程序的运行速度,或者将帐号数据保存到服务器中,这就要考虑到服务器安全和用户信任的问题了。 对于全局变量用于保存用户的默认设置,同样需要从缓存中读取到内存中。 验证页面布局: 采用居中和流式布局(flex) 顶部: 使用一个标签来标识用户的状态(输入密码、设置密码、再输一次、密码错误) 6个圆点表示用户输入的密码个数(填充、未填充),根据密码的长度来做相应的显示 优点1:微信小程序的数据和视图是绑定在一起的,数据的变化会自动更新视图。类似iOS里面的viewModel,通过数据来布局 中部: 使用1~9的按钮作为密码输入控件,采用流式布局 因为使用wx:for来创建的数字输入控件,数据绑定的点击事件为numTap:,对于特殊的符号C,X,0区别对待`,设置不同的颜色和功能 底部: 功能按钮设置(重新输入、指纹识别等),为了避免用户忘记上一次的输入 采用flex布局,后期可以添加新的功能上去,而不用考虑布局 优点2:拥有自动约束的功能,能够为后面的布局自动适配。类似iOS中的storyboard 验证页面逻辑: 使用顶部标签来标记用户的状态,进而进行操作 流程: 页面加载,获取全局变量app.globalData中的userKey,判断用户是否为第一次使用程序(密码为空表示第一次使用程序),设置标签的状态为请设置密码,否则加载userKey,openFingerPrint状态到当前页面。同时如果用户设置了指纹识别,则自动弹出。 输入密码时,根据标签执行不同的方法。 请设置密码:将输入的密码push到pwd ,然后由settingPwd保存到userKey里,这里的pwd作为密码的输入容器,当pwd的长度为6时,切换到再输入一次状态下,执行confirmPwd,当pwd的长度为6时,验证两次输入的密码是否正确,正确:执行setStorageAndLogin保存用户的密码,并跳转到主页面wx.switchTab,关于跳转页面参考开发文档(有几种不同的跳转方式)。这里使用的是关闭当前页面,并跳转到tabbar。错误:清空用户的输入,并振动confirmError。此时用户可以选择返回到上一次的状态,底部的工具按钮会显示clearStoreKey。 用户不是第一次登录时,请输入密码:执行loginPwd,将pwd和userKey比较叫醒相应的操作 清除按钮:在请设置密码的状态下,需要清除userKey,其余状态只需清除pwd即可 删除按钮:在请设置密码的状态下,需要pop userKey,其余状态只需pop pwd即可 重构: 这里用到了一些重构的方法:提炼函数(Extract Method)、塑造模板函数(From Template Method)、过多的注释(Comments) 来自阅读笔记:重构改善既有代码的设计 2. 主页主页布局: 分为一个主页背景&搜索框,帐号分类的九宫格 上部: 采用一个375rpx*200rpx相对像素的图片作为背景,背景上重叠一个半透明的搜索框 解释: rpx表示根据屏幕进行自动适配的像素点,因为点和像素是存在一个比例的。类似iOS里面的屏幕适配,采用的点和像素点之间的转换 微信小程序里面的布局是自动分布下来的,并不会发生重叠。所以需要设置z-index: -1;来调节显示的优先 下部: 一个分割栏,表示分类信息&一个开启随机壁纸的按钮 采用WEUI的九宫格控件来完成,自带navigator,只要放置好URL即可 主页逻辑: 从全局变量加载分类信息&用户设置 流程: 点击搜索框,输入帐号的(名称、帐号、备注)在所有帐号里面返回对应的集合。这里采用了util工具类,对于全局一些常用的功能和方法提取。搜索成功则跳转到对应的页面showAccount,否则弹出相应的提示。 点击九宫格中的分类,跳转到navigator,设置好的URL,然后将分类信息传递到页面showAccount 3.showAccount页面 一个简单的tableList,显示帐号的基本信息(图标、名称、帐号)。右下角提供一个添加帐号的按钮,长按可以删除帐号 showAccount逻辑:流程: 因为该页面包含了从九宫格和搜索框过来的两种情况,需要根据页面传递过来参数来判断。搜索的跳转是不带参数的 每次页面显示都会更新导航栏标题上面,当前分类的帐号数量。是为了当用户移动了帐号的类别,就需要做出相应的改变,这里用到了页面反向传参 九宫格跳转:根据传递帐号的类型accType,通过util工具类,在所有帐号中返回该类型的帐号集合。为空就显示出empty的页面,并提示用户添加帐号。 搜索跳转:通过util工具类,返回包含关键词的帐号,使用到了search(key)来判断一个字符串中是否存在某个字符。因为这里是通过URL跳转的,URL只能是字符串。所以需要将返回的集合进行json化,才能传递。并没有像HTPP那样,可以通过response来传递数据。 长按删除:选择一个帐号长按,会触发showOperation,可以用来删除帐号。删除帐号要注意的是,需要记录帐号在当前集合中的行数,因为所有的帐号的缓存中并没有按照分类来保存,所有的帐号都是保存在一起的。所以显示的顺序和存储顺序并不一致,所以同样通过util工具类,返回对象的位置,并记录。接下来需要做的是: 删除页面例的帐号信息 删除缓存中的帐号信息,这里同样需要找到缓存中当前帐号的位置 更新页面信息(全局变量、帐号数量) 点击显示帐号:记录帐号在缓存中的位置,和当前页面的位置。因为用户可能修改帐号的信息,你需要同步更新(这里用到了逆向传值)。还有就是所有数据都是根据全局变量来做出改变的,并不会继续读取缓存中的数据,为了加快程序运行速度,所以需要同步更新缓存和全局变量。传递到新页面adding_account的参数有帐号的json信息accountJSON、帐号在缓存中的位置accountIndex、帐号的类型accType、帐号在原页面的位置tapIndex、页面类型pageType,因为该新页面提供了两种功能。 解释: 页面正向跳转传参,用到的是基本的URL,通过字符串来传递参数,和HTTP中的TCP类似 反向传参,通过获取页面栈 12345678910var pages = getCurrentPages()var that = pages[pages.length - 2]// 然后就可一像操作上一页面的数据一样即可if (that.__route__ == \"pages/showAccount/showaccount\") { that.setData({ accountList: beforeAccountList, // 这一句代码用于临界情况,该分类下只有一个帐号,将所有情况普通化 emptyInfo: \"暂无 \" + this.data.accType + \" 的帐号\" })} 如何在对象数组中查找对象,数组对象的比较还包括了指针, 所以即使内容完全一样,也无法查找到,原因是因为对象数组中判断两个对象是否相同,这两个数据都必须是该对象数组中的。该对象的数据来源并不一致(即不是同一个数组),所以采用将对象json化,然后进行比较即可。需要注意:json转码中 & ? 等符号不能使用。 that & this 在回调方法中的问题12345678910111213141516/*** 解决方法一* 复制一份当前的对象,如下:* var that=this;//把this对象复制到临时变量that* * 在wx.request({}),有时候会需要获取页面初始化数据data的情况,* 如果使用,this.data来获取,调试页面会报undefiend。* 原因是,在javascript中,this代表着当前对象,会随着程序的执行过程中的上下文改变* 在wx.request({}); 方法的回调函数中,对象已经发生改变,所以已经不是wx.request({});方法对象了,data属性也不存在了。 ** 解决方法二* 将回调函数换一种声明方式* success: res=> {* this.* }*/ 4.adding_account页面 用于显示帐号的详细信息、修改帐号、添加帐号、分享帐号 页面布局: 帐号图标,可以通过右侧的选择图标,从自带的图标或者相册里面获取 分类选择器 帐号名称 帐号 密码位数,滑杆(0~16) 密码规则,用于自动生成密码 密码,通过右侧的生成密码按钮生成密码 备注 操作按钮区域(保存帐号、更新帐号、复制密码) 页面逻辑: 通过util类获取已存在的帐号分类,包括用户自定义添加的类 根据页面的类型pageType,显示不同的信息 显示帐号:将页面传递过来的帐号数据,保存到当前页面,通过控件显示value='' 更新帐号:当用户修改了帐号的信息,通过输入框失去焦点来获取实时的更新内容,保存在account里。然后用户点击更新帐号按钮即可更新完毕。saveAccount这里面处理的有: 判断信息是否为空 特殊符检查,避免json数据传递失败 判断页面状态,是更新帐号 or 添加帐号,进而进行不同的操作 同时为了减少图片的缓存问题,将帐号的icon进行判断(图片 || 已有类型) 根据按钮的类型,进行不同的操作modifyAccount。更新全局信息,上一页面的信息,缓存信息。 保存帐号:和更新帐号采用的是同一个方法,仅仅第五步不同,通过util工具,来添加对象,需要保证不能添加相同的帐号。所以同样需要对象json化,来保证。 总结:随着开发的难度不断减小,得益于开发工具和完善的开发资料。人们对于应用的接入并不在乎是通过小程序,还是原生应用。对于那些使用频率小的应用,更是如此。 未来的开发方向不在由几大平台割裂,我们需要的不是同一个解决方案下的多套代码,我们需要的是开发过程中,通过开发人员不断完善和统一的开发平台。 或许我们可以通过AI和开发各个领域的高级开发工程师,来不断向这个目标靠近,开发出一个强大的AI开发平台,区分的仅仅是逻辑而不是标准。 核心问题: 处理边界情况 数据更新,页面传值、工具类封装 页面布局 压缩工程体积,用户体验,UI界面 开发问题: 控件布局 应用处理逻辑 开发工具的利用(主要是调试) 扩展和深入: 对于项目里面提供的常用帐号图标,来自与网页应用市场,然后通过编写python脚本来进行一键处理(背景透明化、大小设置) 使用工具将图片进行压缩,降低工程的体积 下一步,考虑使用服务器(腾讯云或者阿里云) 参考资料: 微信小程序 View:flex 布局 关于微信小程序文字水平垂直居中 微信小程序之让view水平垂直居中","categories":[{"name":"开发总结","slug":"开发总结","permalink":"https://ilifexiao.github.io/categories/开发总结/"}],"tags":[{"name":"微信小程序","slug":"微信小程序","permalink":"https://ilifexiao.github.io/tags/微信小程序/"}]},{"title":"计算理论","slug":"计算机科学概论/第十二章、计算理论","date":"2018-06-20T03:27:42.000Z","updated":"2018-07-11T06:10:59.000Z","comments":true,"path":"2018/06/20/计算机科学概论/第十二章、计算理论/","link":"","permalink":"https://ilifexiao.github.io/2018/06/20/计算机科学概论/第十二章、计算理论/","excerpt":"","text":"第十二章、计算理论 奠定了计算科学真正的科学地位 将讨论有关编程语言能力的内在问题 1. 函数及其计算 理解计算机能做什么和不能做什么,以及机器要实现其全部潜能需要哪些特征 函数:可能输入值和可能输出值之间的一种对应关系 对于那些过于复杂以致找不到定义的明确的函数,超过了任何算法的能力范围,成为不可计算的函数 2. 图灵机 用作研究算法处理能力的一种工具 2.1 图灵机的原理 计算开始与一个初始状态,和结果处于停止状态 由控制单元控制执行步骤,左移或右移,来写入数据 2.2 丘奇——图灵论题 图灵机的计算能力囊括了任何算法系统的能力 这个猜想的意义在于,他认识到了计算机器的能力和局限性 3. 通用程序设计语言 如今的许多高级语言知识增强的使用的方便性,对语言的基本功能并没有什么贡献 3.1 Bare Bones语言 从通用设计程序语言中分离出来的需求的最小集合 1. 变量类型 二进制 无需类型转换 12clear Xincr X 2. 赋值语句123456# 清空变量为0clear name# 增加incr name# 减少decr name 3. 控制语句 只提供一条控制语句 12while name not 0: #do something 3.2 用Bare Bones语言编程 提供了一种基本的通用程序设计语言 例子1 赋值操作,将A的值赋值到B 但是会破坏原来A的值 1234clear Bif A not 0: incr B decr A 例子2 为了不破坏原有的数据,引入了临时变量 通过定义一鞥关键字,来创建一个新的语法copy name1 to name2 123456789clear Cclear Bif A not 0: incr C decr Aif C not 0: incr A incr B decr C 3.3 Bare Bones的通用性 研究证明,Bare Bones可以用来表示所有的可计算函数的算法 在计算科学理论的研究中常常用到 4. 不可计算函数4.1 停机问题 一个程序在某些条件开始后,是否能够终止 存在一个单一的、通用的却能够适用于所有情况的算法 例子 如果程序不是以0 开始的,那么程序将不会终止 12while x not 0: incr x 可以看出程序能否终止取决于它初始变量的值 自引用技术(self-reference) 思想在与一个对象引用自己 自引用的例子 产生了悖论 “这条语句是错的“ “所有集合的集合是否包含其自身” 但是 对于这个程序,无论初始值为什么,都会终止 123clear xwhile x not 0: incr x 所以引出以下的定义——自终止(self-terminating) 这是一个属性,要么是,要么不是 如果一个程序中的所有变量都是用程序自身的编码表示来进行初始化的,且这个程序的执行能够导致一个终止的过程 所以 停机问题可以描述为,一个程序是否为自终止的 但是没有一个单一的算法可以确定这个程序是否为自终止的——停机问题超出了计算机的能力 我们只能解决特定问题的下的方案,并没有普遍适用的方法 4.2 停机问题不可解性 利用反证法,先假设存在这样的程序 5. 问题的复杂性 不能在合理的时间上解决的问题,在实际观点上来看是无解的 5.1 问题复杂性的度量 问题的复杂性取决于算法的特性 复杂性解释倾向于度量一个算法在表示中所遇到的难度,而不是算法本身的复杂性 复杂性最终相关的是机器在执行一个算法所花费的时间,而不是用来表示解的程序的大小 所以能,又有时间复杂性:定义为一个问题最优解的时间复杂性 但是,寻找一个程序的最优解和确认是程序的最优解本身就是一个难题 所以,使用O(f(n))表示这个问题的复杂性为O(f(n)),但是他还有可能有其他更优的解 时间复杂性和空间复杂性之间的折中 5.2 多项式问题和非多项式问题 如果一个问题是属于$$O(f(n))$$的,其中表达式$$f(n)$$要么是宇哥多项式,要么就是受多项式约束 特征是,具有极长的执行时间 P问题是一个判定问题类,这些问题可以用一个确定性算法在多项式时间内判定或解出。如果一个判定性问题的复杂度是该问题的一个实例的规模n的多项式函数,则我们说这种可以在多项式时间内解决的判定性问题属于P类问题。P类问题就是所有复杂度为多项式时间的问题的集合。 确定一个问题是否是多项式问题,在计算机科学中非常重要。已经证明,多项式问题是可解问题,因为除了P问题之外的问题,其时间复杂度都很高,即求解需要大量时间。 理论上有解但其时间复杂度巨大的问题,科学家将其称为难解型问题。对计算机来说,这类问题是不可解的。因此,P问题成了区别问题是否可以被计算机求解的一个重要标志。 5.3 NP问题 NP问题是指可以在多项式时间内被非确定机解决的问题。通常它们的时间复杂度都是指数变量,,如$$O(2^n)$$等 旅行推销员问题(英语:Travelling salesman problem, TSP)是这样一个问题:给定一系列城市和每对城市之间的距离,求解访问每一座城市一次并回到起始城市的最短回路。它是组合优化中的一个NP困难问题,在运筹学和理论计算机科学中非常重要。 在非确定性的算法下和确定性算法下,存在明显的界限,非确定性算法依赖于计算机的创造性(运气?) 目前已经证明所有P问题都是NP问题,那么反之P—NP吗?这就是所谓的“NP问题”。目前P与NP是否等价是一个既没有证实也没有证伪的问题。但是大部分科学家猜想:找一个问题的解很困难,但验证一个解很容易(证比解易),用公式表示就是P≠NP。 问题较难求解(P)但容易验证(NP),这与我们的日常生活经验是相符的。 6. 公钥密码学 利用了问题难解易验证的特性 比如寻找某个大整数的因数 在密码学领域里,被用作RSA算法 6.1 模表示法 如果p&q都是素数,m是0到pq的一个整数,那么,对于任意的正整数K,就有$$1 = m^{k(p-1)(q-1)}\\% pq$$ 6.2 RSA公钥密码学 两个素数p和q,n = p*q,两个正整数e,d,k,满足 $$e*d=k(p-1)(q-1)+1$$ 这里选取了5个值,p、q、n、e、d。e、n是加密密钥,d、n是解密密钥,p、q只是用来构建加密系统 加密 位模式(ASCII、Unicode)编码,值小于n(如果大于n,则需要分段) 设报文的值为m(m<n),则,加密后的报文为$$c=m^e \\% n$$ 解密 解密的值为:$$c^d\\%n$$,余数就是加密前的值 利用了$$1 = m^{k(p-1)(q-1)}\\% pq$$ $$c^d\\%n=m^{ed}\\%n=m^{k(p-1)(q-1)+1}\\%n=mm^{k(p-1)(q-1)}\\%n=m*m^{k(p-1)(q-1)}\\%pq=m$$ 破解 通过对n进行因式分解,得到p&q,了解到解密的过程中$$c^d\\%n$$,像办法得到d, 找出一个k值,使得k(p-1)(q-1)+1能够被e整除(商就是d ),$$k(p-1)(q-1)+1 \\div e =d$$ 但是在与隐式分解的难度,可能需要好几年才能破解完成 例子(p=7,q=13,n=91,e=5,d=29) 10111 -> 23 -> $$23^e=23^5=6436343$$ -> $$23^5 \\% n = 23^5\\%91=4$$ -> 100 $$4^d=4^{29}=288230376151711744$$ -> $$4^29 \\% n = 4^29 \\% 91=23$$ -> 10111","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"人工智能","slug":"计算机科学概论/第十一章、人工智能","date":"2018-06-18T13:28:35.000Z","updated":"2018-07-11T06:09:23.000Z","comments":true,"path":"2018/06/18/计算机科学概论/第十一章、人工智能/","link":"","permalink":"https://ilifexiao.github.io/2018/06/18/计算机科学概论/第十一章、人工智能/","excerpt":"","text":"第十一章、人工智能 建造自主的机器人——能够感知和推理 1. 智能与机器 融合了心理学、神经学、数学、语言学以及机电工程学等其他学科相融合 1.1 智能体(agent) 对环境做的刺激做出响应的“装置” 智能体的学习形式1. 过程性知识(procedural knowledge) 反复试验的过程,出错受罚、正确奖励的过程中学习适当的反应 2. 陈述性知识(declarative knowledge) 扩充或者更新智能库里的知识 1.2 研究方法1. 工程路线 侧重开发展示智能的系统 目标是生产出符合某些性能目标的产品 2. 理论路线 尝试从计算机的角度来研究人类(动物)的智能 关注重点在于增进人类对计算智能的理解 产生了面向模拟的方法论 例子 自然语言处理和语言学领域 1.3 图灵测试 图灵测试的重要性已不如从前,但它仍是人工智能领域重要的一部分 一个原因在于,相对简单的手法会产生怪诞的智能显示 如DOCTOR程序——一个心里治疗对话程序 2. 感知 理解图像、理解语言是感知研究领域中特别具有挑战性的 2.1 理解图像1. 图像处理(image processing) 标识图像的特征 2. 图像分析(image analysis) 理解特征代表什么意思的过程 在这个过程中,用到了轮廓增强、平滑 2.2 语言处理1. 句法分析(syntactic analysis)2. 语义分析(semantic analysis)3. 上下文分析(contextual analysis)信息检索 标识与手头论题有关的文档 信息提取 为一个特定的问题确定答案,或者将信息以某种格式记录,以备日后解答问题时使用 语义网 3. 推理3.1 产生式系统1. 状态集合 标识初始状态、和目标状态 2. 产生式集合3. 控制系统 开发的一个重要的概念是问题空间(problem space) 问题空间通常会概念化成为状态图(state graph) 推理法则:离散数学里的推论 3.2 搜索树 alphgo,围棋,就是应用了搜索树 3.3 启发式法 为了应对庞大的搜索树,重新设计搜索树的构建方法,从广度优先,到深度优先,使得路径向我们希望的方向发展,通常称为最佳优先(best-first) 对规划待机的一个衡量 两个特征 对工作量具有一个合理的估计 应该容易计算 基于行为的人工智能 为什么冯·诺依曼体系结构的机器在计算能力上轻易胜过人类,却难以展示常识性的判断 基于行为的技术:人工神经网络领域、遗传算法领域、机器人领域 4. 其他研究领域4.1 知识的表达和处理 知识仓库:真实世界的知识,由人脑维护 人类一某种方式存储大量的信息并且一极高的效率从这些信息中汲取有用的信息——人工智能的一个重要挑战 潜在的目标是找到表示和存储知识的途径,但是很复杂 同时需要让知识容易理解,但是获取这种理解是一种挑战 还有一个问题是,知识的确定不是明确的,而是含蓄的,是有手头任务相联系的 元推理(meta-reasoning) 关于推理的推理 数据库搜索最初使用的是封闭世界假设(closed-word assumption),先假设一个语句为假,除非他能够从可用的信息明确得出 但是存在一个矛盾,Mickey is a mouse or Donald is suck,但是他会推断出,两个都为假,虽然两个句子中至少可以有一个为真 还有一个称为框架问题——用来在变化的环境中,使知识保持最新 4.2 学习学习的层次 模仿 监督训练 强化——得到一个一般的规则,指导自己进行判断 逻辑程序设计知识 知识的表达和存储与知识的提取和应用过程很好地整合在一起 如:Dumbo is a elephant,和 X is a elephant implies X is a gray 发现 一个与学习紧密相关的一个现象 计算机发现系统中成功的例子包含哲学家弗朗西斯·培根爵士命名的Bacon,他已经能够发现电学上的欧姆定律、行星运动的开普勒第三定律、动量守恒 系统AUTOCLASS,它采用红外光谱数据,发现了现在在天文学上未知的新型恒星,这是由计算机完成的一个真正的科学发现 4.3 遗传算法 A*算法壳寻找许多搜索问题的最优解,但是一些问题过于复杂,难以求解(超出内存、无法在合理的时间内完成) 可以通过一个包含多级试探解的演进过程获得解——遗传算法(genetic algorithm) 遗传算法,通过猜测,随机给出一些解,通过从上一代的染色体中选择最有可能的染色体跳出两个作为父辈(最难的部分),不断进化 5. 人工神经网络 提供了模仿活体生物系统中神经网络的模型 一个人脑大约有 $$ 10^{11} $$个神经元,每个神经元有$$10^4$$个突触 v1、v2、v3表示其他神经元的输出 w1、w2、w3表示权重(可正可负) 5.2 训练神经网络 不在通过传统意义上的编程来实现,而是通过训练来实现 5.3 联想记忆 神经元相互连接没有输入和输出的网 6. 机器人学 研究具有智能行为的物理上的自主智能题的一门学科 对于所有智能体,机器人在所处的环境中必须能够感知,推理和发生作用 涵盖了人工智能的所有研究范围,并借鉴了很多机械和电子工程方面的知识 自主机器人 计划周密的 反应型机器人,这个比较像人类 进化型机器人7. 后果的思考 人类的价值观和人工智能的价值观 是否符合社会道德","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"计算机图形学","slug":"计算机科学概论/第十章、计算机图形学","date":"2018-06-17T07:23:41.000Z","updated":"2018-07-11T06:10:48.000Z","comments":true,"path":"2018/06/17/计算机科学概论/第十章、计算机图形学/","link":"","permalink":"https://ilifexiao.github.io/2018/06/17/计算机科学概论/第十章、计算机图形学/","excerpt":"","text":"第十章、计算机图形学 许多人认为计算机动画在不久将来会取代整个影视产业对传统的演员、布景和照片的需求 计算机图形学包含的方面: 图形、图表 图形化用户界面的开发 照片的操作 视频游戏的制作 动画电影的生成 1. 计算机图形学的范畴2D图形学 用于生成图像 图像处理 用来图像分析,进行模式识别 3D图形学 建造三维场景的数字编码版本,然后模拟照相的过程,产生这些场景的图像 适用于交互视频游戏和动画电影 三维人机接口 2. 3D图形概述创建和显示的过程1. 建模 由数字编码数据和算法构成 2. 渲染 通过投影显示二维图像,还要取决于你的图像视窗的大小,来显示不同的样貌 还需要计算场景中物体和光线如何交互 当确定了每个像素的外观后,结果被表示为图像的位图,集中存储在称为帧缓冲区(frame buffer)的存储区中 3. 显示3. 建模 3D计算机图形学的其实阶段与戏剧舞台制作方式十分相似:必须设计出布景,收集或者搭建所需的道具 在计算机图形学中的术语,布景成为场景(scene),道具成为物体(object) 3.1 单个物体建模3.1.1 形状 网格表示所有物体的形状确立了渲染处理的同意方法——可以更高效地渲染整个场景 在3D图形中的物体的形状通常被描述成称为平面片(planar patch),的小平面集合,期中每一个都是一个多边形。这些多边形形成了多边形网络(polygonal mesh),被近似于描述物体的形状。通过使用小平面,近似值可以达到所需的精度。 多边形网格中的平面片经常选择三角形,因为在三维空间中最少使用三个点表示一个平面 一个物体的多边形网格可以展现可以通过多种途径获得,如:以所需形状的精确的集合描述开始 $$ r^2 = x^2+y^2+z^2 $$ 基于这个公式,我们可以建立球上的经线和纬线方程,标识这些线的交叉点,然后使用这些点作为多边形网格中的顶点 更一般的形状可以使用更复杂的分析方法来描述贝赛尔曲线 在三维空间中只用几个称为控制点的点来定义曲线段(两个点表示端点,其他点表示曲线的弯曲方式) 贝塞尔曲面可以用来获得复杂表面的网格信息 蛮力获取物体表面的多边形结构 通过类笔设备触摸表面,记录模型表面点的位置 对于非常复杂,难以用集合建模或手工数字化获得模型 通过编写自动构建所需形状的程序——程序化模型(procedural model) 对于相似而又唯一复杂的对象,使用分支规则,即语法分析器构建对象 粒子系统 将物体的基础结构模拟为一个大的粒子集合 通过预定义的规则去移动系统中的粒子,来生成所需的形状 如水、火苗的闪烁、云、拥挤的人群 分型 豪斯多夫维数大于其拓扑维数的几何物体 科赫雪花,通过重复地用相同的结构的较小版本替换结构中的直线段二形成的 在3D图形领域经常是程序化模型的主干,用于生成山脉、蔬菜、云和烟的图像 3.3.2 表面特征 通过纹理映射,将图像与一个物体的表面相关联 在平坦的表面,纹理映射效果最好。如果必须大幅扭曲纹理图像区覆盖弯曲的表面,在接缝出纹理模式可能不与它本身融合,效果会不够逼真 3.3.3 寻求逼真的效果 人类皮肤的逼真模型(光渗透的表皮和真皮层的程度) 头发(对风的外力、半透明特性、纹理深度、悬垂性) 布(纹理、机械工程知识(拉伸、修剪等)) 3.2 整个场景的建模 当场景中的物体得到充分的描述和数字化编码,被赋予了位置、大小和方向——场景图(scene graph)的数据结构 包含与光源的特殊物体及表示相机的特殊物体的链接,期中记录了相机的位置、方向和焦点等特性 类似传统的摄影工作室,但场景图描述的是一个虚拟的世界 前景比背景更需要精度 另一个设想是,场景由智能模型构成,会根据相机的移动,改变自身的特性 4. 渲染 物体的外观是由物体发出(反射)的光决定的 4.1 光-表面交互 照射到物体表面的光可能被反射、吸收、穿过等 4.2 裁剪、扫描转换和隐藏面的消除 渲染流水线,通过一个投影中心形成的椎体,可以不用考虑椎体外边的物体(称为裁剪) 然后确定剩余平面上的点,将像素和场景中的点关联起来(称为扫描转换),像素越高,渲染细节就越多 也就是用到投影的技能,用光栅来表示 然后还要去除那些被遮挡的点(称为隐藏面消除) 关于隐藏面消除有许多做法,比如后面消除法、画家算法、Z缓冲区 4.3 着色 平面着色,表示的是多边形网格本身的图像,而不是用网格建模的物体图像 Gouraud着色、Phong着色 凹凸映射,表面外观朝向加上一个小的变量 4.4 渲染——流水线硬件 只实现了局部照明模式,对于全局照明模式,没有考虑到两个物体之间的交互 在电子电路中实现了,通过超大规模集成电路(VLSI)技术已经被微缩为芯片,自动完成整个渲染线的工作 GPU 为了减少对特定图形平台的依赖,使用了(OpenGL、Direct3D等标准软件接口) 但对于物体的交互,在这常常用时模拟投影,来实现 5. 处理全局照明 光线跟踪、辐射度;两种方法都极为精准,但是费时 光线跟踪 沿着光线反向跟踪以找到他的光源的过程 缺点是只跟踪镜面反射,可以通过分布式光线跟踪来去除这种效果 通过递归调用来找到光源,费时,一般在电影工作室使用 辐射度 考虑通过两个平面片对之间的辐射光能的总和,采取了更加区域化的方法 辐射的光能本质是散射光 一个物体对另一个物体的影响程度称为形状因子(form factor) 因为需要考虑许多面片,计算量是很大的 优点在与物体的显示不受相机的影响,捕获了光的许多微特征,如渗色(color bleeding) 6. 动画","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"数据库系统","slug":"计算机科学概论/第九章、数据库系统","date":"2018-06-16T05:40:25.000Z","updated":"2018-07-11T06:11:48.000Z","comments":true,"path":"2018/06/16/计算机科学概论/第九章、数据库系统/","link":"","permalink":"https://ilifexiao.github.io/2018/06/16/计算机科学概论/第九章、数据库系统/","excerpt":"","text":"第九章、数据库系统 数据库的研究钟重点在于开发一些技术,把数据库中的信息提供给决策过程 数据挖掘 涉及计算领域、统计领域 许多领域的重要工具 市场营销 库存管理 质量控制 借贷风险 欺诈检测 投资分析 确定某些以DNA分析进行编码的基因功能 常见的形式 类描述 类识别 聚类分析 关联分析 孤立点分析(异常检测) 序列模式分析(经济趋势、环境趋势) 数据可技术对社会的影响 个人信息收集 隐私问题","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"数据抽象","slug":"计算机科学概论/第八章、数据抽象","date":"2018-06-11T04:33:22.000Z","updated":"2018-07-11T06:12:02.000Z","comments":true,"path":"2018/06/11/计算机科学概论/第八章、数据抽象/","link":"","permalink":"https://ilifexiao.github.io/2018/06/11/计算机科学概论/第八章、数据抽象/","excerpt":"","text":"第八章、数据抽象 数据结构,潜在主题是抽象的工具的构建 1. 基本数据结构 数组和聚合 列表、栈和队列 树 2. 相关概念2.1 抽象 计算机的主存储器是由一组壳寻址的存储单元顺序组成的,其他的数据结构都必须进行模拟,使用户不必关心实际数据存储的节点 2.2 静态结构与动态结构 考虑数据结构是否会发生改变 2.3 指针 用于记录数据项的存储位置 比如在更新移动一个数据的位置,通常通过更新指针的地址 CPU指令执行的指令指针 3. 数据结构的实现 数组(连续的地址) 聚合存储(指针) 存储列表(链接表、链表) 存储栈和队列(Top指针、两个指针) 二叉树(数据单元、左指针、右指针)(不用指针的存储的树) 3.1 操控数据结构 二分搜索算法(可以通过二叉树来实现) 方法 约定,当列表的一部分为偶数项时,区中间两项例最大的为中间项 将列表的中间项成为根节点 然后把余下的左半部分的中间节点作为左子节点 右半部分的中间节点作为右子节点 二分搜索用于作为炼石二叉树实现的列表123456789def Search(Tree, TargetValue): if (Tree is None): return None elif (TargetValue == Tree.Value): return Tree elif (TargetValue < Tree.Value): return Search(Tree.Left, TargetValue) elif (TargetValue > Tree.Value): return Search(Tree.Right, TargetValue) 垃圾回收 由于动态数据结构的增大和缩小,存储空间也不断地占用或释放,所以需要回收不用的存储空间 否则的话,会导致内存泄露(memory leak) 用于打印二叉树中数据的函数12345def PrintTree(Tree): if (Tree != None): printTree(Tree.Left) print(Tree.Value) printTree(Tree.Right) 一个用于向二叉树存储的列表中插入新的项的函数1234567891011def Inster(Tree, NewValue): if (Tree is None): Tree = TreeNode() Tree.Value = NewValue elif (NewValue > Tree.Value): Insert(Tree.Right, NewValue) elif (NewValue < Tree.Value): Insert(Tree.Left, NewValue) else: print(\"find Next\") return Tree 5. 定制的数据类型 为了更好地满足某个具体应用的需求,自定义一些数据类型 比如结构体 定义了一个新的聚合1234567struct { char name[25]; int age; float skillRating;} Employee;Employee employee1; 没有定义新的聚合1234567struct EmployeeType { char name[25]; int age; float skillRating;};struct EmployeeType employee1; 抽象数据类型(ADT) 以实现一个堆栈来说明 1234567891011121314151617struct StackType { int StackEntries[20]; int StackPointer = 0;} Stack;Stack StackOne, StackTwo, StackThree;// 我们向隐藏堆栈的使用细节,比如插入push()// 所以我们需要实现这个方法,缺点在与这个类型并不具有方法的功能push(int value, Stack stack) { if (stack.StackPointer >= 19) { printf(\"stack is full\"); return } stack.StackPointer ++; StackEntries[stack.StackPointer] = value;} 在JAVA中 我们可以通过接口来实现,或者通过类(面向对象的思维来实现) 123456interface StackType { public int pop(); public int push(); public int isempty(); public int isFull();} 6. 类和对象 类和对象的概念体现了成勋中数据抽象的表示技术又前进了一大步 7. 机器语言中的指针 立即寻址 直接寻址 间接寻址","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"软件工程","slug":"计算机科学概论/第七章、软件工程","date":"2018-06-10T11:36:22.000Z","updated":"2018-07-11T06:11:32.000Z","comments":true,"path":"2018/06/10/计算机科学概论/第七章、软件工程/","link":"","permalink":"https://ilifexiao.github.io/2018/06/10/计算机科学概论/第七章、软件工程/","excerpt":"","text":"第七章、软件工程 计算机学科中的一个分支 致力于寻找大型复杂软件系统的开发原则 包含人员管理、项目管理之类的主题 1. 软件工程学科 与其他工程学科之间的一个差别在于缺少衡量属性的定量技术——度量学(metrics) 同时也出现了计算机辅助软件工程(CASE)、IDE 通用也有ISO、ACM、IEEE等组织来指定标准、提供方针、增强人们的职业精神 2. 软件生命周期 软件工程中最基础的概念 开发 -> 使用 维护 2.1 传统的开发阶段1. 需求分析2. 设计3. 实现4. 测试3. 软件工程方法学4. 模块化 把软件分割成多个易于处理的单元 降低软件之间的耦合 提高内部绑定程序的关联度 隐藏软件的信息(封装) 耦合的形式 控制耦合 数据耦合 5. 行业工具 通过数据流图,确定业务的流程,以及理解系统(同时也作为客户与软件工程师之间的交流手段) 构建统一的建模语言(UML/ER等) 设计模式 6. 质量保证 软件质量保证,开发记录、标准指定等 软件测试:白盒测试、黑盒测试 7. 文档分类 用户文档 系统文档 技术文档 8. 人机界面 主要来于人机工程学和知行学 界面上呈现的东西应该不依赖于人类的记忆 9. 软件所有权和责任 知识产权 软件许可 专利问题","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"程序设计语言","slug":"计算机科学概论/第六章、程序设计语言","date":"2018-06-09T08:21:33.000Z","updated":"2018-07-11T06:11:39.000Z","comments":true,"path":"2018/06/09/计算机科学概论/第六章、程序设计语言/","link":"","permalink":"https://ilifexiao.github.io/2018/06/09/计算机科学概论/第六章、程序设计语言/","excerpt":"","text":"第六章、程序设计语言 了解程序设计语言及其相关联的方法之间的共性 1 历史回顾1.1 早期程序设计语言 程序设计语言的发展并没有那没容易,通过自然语言的形式来编写程序是革命性的 机器语言 -> 汇编语言 -> FORTRAN(科学和工程应用) & COBOL(美国海军为商业应用开发的) -> 通过编译器来将高级原语表示成机器语言,另一种代替翻译器的是解释器(interpreter)在翻译指令的同时执行指令 1.2 机器无关和超越机器无关 程序设计语言的机器无关特性和解决问题的角度来进行思考的程序来决定的 由于底层及其的设计并不相同,所以对于跨平台来说程序并不兼容 后面由一些国家标准学会和国际化标准组织公布一些标准 但是编程的思想是相同的,高度和平台无关 1.3 程序设计范例 说明性范型 -> 命令型范型 -> 面向对象范型 -> 函数式范型 命令型范型 也称为过程范型,如Python为它的一个子集 是一个开发命令的序列 说明性范型 与命令型范型相对应 通过描述问题,然后通过预先设定好的通用算法来解决问题 一般都是用于特定的领域(政治、经济、环境等) 函数式范型 通过接受输入来完成输出的实体 通过函数的组合来完成程序设计 面向对象范型 将软件看做一个对象的集合,类似一个生态系统 2. 语言实现2.1 翻译过程源程序 -> 词法分析器 -> 语法分析 -> 代码生成器 -> 目标程序 多线程 增加了对自身访问的控制能力的数据项成为监控程序(monitor) 离散数学 Prolog 语言 逻辑程序设计","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"算法","slug":"计算机科学概论/第五章、算法","date":"2018-06-07T08:06:19.000Z","updated":"2018-07-11T06:15:28.000Z","comments":true,"path":"2018/06/07/计算机科学概论/第五章、算法/","link":"","permalink":"https://ilifexiao.github.io/2018/06/07/计算机科学概论/第五章、算法/","excerpt":"","text":"第五章、算法 计算机科学的核心是算法核心 许多研究人员相信,人脑中的活动,包括幻想、创造和决策,实际上都是算法的执行结果 1. 算法的正式定义 可终止过程的一组无歧义的、可执行的步骤的有序集合 当然包也有不确定算法 同样有那些用算法无法解决的问题 2. 算法的抽象本质 程序是一个算法,算法的表示方式有很多种,比如数学公式,图解等 3. 求解问题的艺术 在求解问题之前,需要充分理解问题的(虽然在解决问题之前难以真正地理解问题,所以这两种情况应该相辅相成),避免造成资源浪费 对于一个还没有完成的任务,然后去做其他事情,可能会在完成其他事情之前就想到刚刚问题的解决方案(沉思期),潜意识在不断地工作 3.1 卖迈出第一步 就是动手解决现在能够解决的问题 逐步求精 将问题分为多个子问题,逐步解决,也就是自顶向下 自顶向下和自底向上是计算机科学中终重要的方法 4. 迭代结构 一组指令以循环的方式重复执行 4.1 顺序搜索算法 按照顺序进行查找 4.2 循环控制 前测试循环(pretest loop) 后测试循环(posttest loop) 4.3 插入排序算法 在一个存在的序列里面进行排序,并不大量使用其他空间 4.4 递归结构 迭代和递归的等价性 二分查找 1234567891011121314def search(List, targetValue): listLen = len(List) if (listLen == 0): return -1 else: testEntry = List[listLen/2] if (testEntry == tatgetValue): return list/2 if (testEntry > tatgetValue): newList = List[listLen/2 + 1:] search(newList, targetValue) if (testEntry < tatgetValue): newList = List[:listLen/2 - 1] search(newList, targetValue) 4.5 递归控制 必须要有一个能够结束递归的条件,否则将陷入无限地调用 5. 效率和正确性5.1 算法效率 时间复杂度和空间复杂度 对于二分查找的效率为 $$ log_2 n $$ 5.2 软件验证例子 一位拿着由7个金环组成的链子的旅行者必须在一个酒店里住7也,每一夜的 租金是金链中的一环,应该怎样对链子进行最少次数的切割,旅行者才能每天早 上支付饭店的一环而不用提前支付住宿费? 解决 只要切开第三环即可,通过不断地交换金环就行了 思考 正确的程序往往和我们的想法一些出入,那些看似正确的方法离真正的解决方案还是有一段距离的,目标是用形式逻辑来证明程序表达的算法确实做了它试图做的工作 质量的优秀十分依赖于测试,断言(assertion)","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"组网及因特网","slug":"计算机科学概论/第四章、组网及因特网","date":"2018-06-06T09:47:55.000Z","updated":"2018-07-11T06:10:44.000Z","comments":true,"path":"2018/06/06/计算机科学概论/第四章、组网及因特网/","link":"","permalink":"https://ilifexiao.github.io/2018/06/06/计算机科学概论/第四章、组网及因特网/","excerpt":"","text":"第四章、组网及因特网1. 网络基础1.1 网络分类范围 个人域网(PAN) 局域网(LAN) 城域网(MAN) 广域网(WAN) 领域 开放式网络 专用网络 1.2 网络拓扑 总线 星型(随着个人计算机的流行,开始流行) 2. 协议 为了网络运行可靠,所建立的网络活动规则 在总线型拓扑中,使用的是 带冲突检测载波侦听多址访问 CSMA/CD(Carrier Sense, Multiple Access with Collision Detection) 在星型拓扑中,使用的是 带冲突避免的载波侦听多址访问 CSMA/CA(Carrier Sense, Multiple Access with Collision Avoidance) 3. 组合网络中继器 在两个中线之间简单地传递信号 网桥 类似中继器,带有检测报文的目的地址,可以不互相干扰对方的网络 交换机 本质上就是具有多连接的网桥 可以连接多个总线 互联网(internet) 注意区分和因特网(Internet),I是大写的,指的是一种独特的、世界范围的互联网 一个网络与互联网链接的“点“称为网关(gateway) 网络之间通过路由器连接起来形成互联网 4. 进程之间通信的方法 进程之间通信通常采用C/S架构 还有一种是对等服务P2P(peer-to-peer),表示通过对等模型通信而不是通过对等网络通信 5. 分布式系统 集群计算指的是一种分布式系统,由多个独立的计算机密切合作,有着成本低、稳定性高、维护成本低等优点,同时具有高可用性(不会因为一台计算机发生故障就不能使用)和负载平衡(自动分配压力) 网格计算,通过分享自己闲置的计算机资源,如威斯康星大学的Condor系统和伯克利开放式网络计算平台BOINC,凭借云计算,将计算机资源按需分配,就像水电一样 6. 因特网(Internet) 起源于20世纪60年代的研究项目,由美国政府资助,通过美国国防高级研究计划局发起 Internet2 第二代因特网,被定义为纯学术系统,目标是对高带宽通信的因特网应用,如远程医疗 6.1 因特网的体系结构 通过ISP来提供网络服务 由于较旧的网络服务基础,通常会有最后一英里的问题,通过DSL调制解调器、电缆调制解调器、卫星上行链路、光纤入户等解决 6.2 因特网编制 IP(Internet Protocol),现在用的是IPV4的32位编码模式 ,后面将采用IPV6的128位编码模式 由因特网名称与数字地址分配机构(Internet Corporation for Assigned Names and Numbers, ICANN)来分配IP地址 通常使用点分十进制来记住IP地址,通过域名服务器 来完成域名到IP地址的转换 6.3 因特网应用 新闻网络传送协议(Network News Transfer Protocol, NNTP) 文件传送协议 (File Transfer Protocol, FTP) 远程登录(Telnet) 安全外壳(SSH) 超文本传输协议(Hyper Text Transfer Protocol, HTTP) 简单邮件传送协议(Simple Mail Transfer Protocol, SMTP) 因特网邮件访问协议(Internet Mail Access Protocol, IMAP) 邮局协议第三版(Post Office Protocol version 3, POP3) 即时聊天(instant Messaging, IM) 因特网语言协议(Voice over Internet Protocol, VoIP) VoIP 在美国,拥有国家传统电话公司的政府把VoIP看做一种威胁,对他们征收很高的税,或者宣布不合法 有三种类型:VoIP软电话(soft phone)、模拟电话适配器(analog telephone adapter)、嵌入式VoIP电话 许多的流媒体服务(视频),采用单播、多播技术,CDN(content delivery network)来均衡负载 7. 万维网 源于 蒂姆·伯纳斯-李 所作出的努力 通过浏览器提供的 URL 来访问信息 HTML & XML 等协议,由W3C制定,","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"操作系统","slug":"计算机科学概论/第三章、操作系统","date":"2018-06-06T09:01:57.000Z","updated":"2018-07-11T06:11:17.000Z","comments":true,"path":"2018/06/06/计算机科学概论/第三章、操作系统/","link":"","permalink":"https://ilifexiao.github.io/2018/06/06/计算机科学概论/第三章、操作系统/","excerpt":"","text":"第三章、操作系统1. 软件分类 应用软件和实用软件之间的界限是模糊的,比如Windows的浏览器是实用软件,还是作为微软打压其他市场的软件 1.1 应用软件 第三方软件 1.2 系统软件 实用软件 操作系统 2. 操作系统的组件内核(Kernel)包含的组件 文件管理程序(file manager) 设备驱动程序(外部设备) 内存管理程序(页面调度,virtual memory:能够提供超出内存的服务) 3. 系统启动 boot strapping 引导,简称:booting 将操作系统引导到主存储器,其中主存储器的一部分 ROM,用来表示CPU初始必须找到的程序的位置 同时对于ROM还有基本输出输出(I/O),在操作系统被引导之前就启动 就是现在流行的BIOS(Basic Input/Output System)或者EFI(Extensible Firmware Interface)、以及许多嵌入式设备的通用固件环境CFE(common firmware environment) 4. 程序调度死锁 满足以下所有的条件的才会出现死锁 存在对不可共享资源的竞争 这些资源的分配不是完整的 一个资源一旦被分配,那么就不能强制收回 5. 安全性 可靠软件的开发不在受牵制与操作系统,它贯穿与整个软件的开发过程,成为软件工程 思考 在瓦尔登湖一书中,梭罗认为,我们已经变成自己工具的工具;也就是说,我们为了使用工具,需要付出的其他成本","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"数据操控","slug":"计算机科学概论/第二章、数据操控","date":"2018-06-03T12:11:59.000Z","updated":"2018-07-11T06:11:55.000Z","comments":true,"path":"2018/06/03/计算机科学概论/第二章、数据操控/","link":"","permalink":"https://ilifexiao.github.io/2018/06/03/计算机科学概论/第二章、数据操控/","excerpt":"","text":"第二章、数据操控指令集 RISC(精简指令集计算机) CISC(复杂指令集计算机) 机器指令分为三类:一、数据传输类 将一个数据从一个位置移动到另一个位置 各种I/O操作 二、算数逻辑类 基本的算数运算 bool 运算 位移(SHIFT、ROTATE) 三、控制类 jump/branch等 程序执行CPU内部的两个专用寄存器:指令寄存器、程序寄存器,一个用于存储当前执行的指令,另一个用于包含一下条执行的指令的地址 机器周期取址 -> 译码 -> 执行 比较计算机的能力 计算机的时钟(clock)是一个振荡器的电路,能够生成用于协调机器活动的脉冲——执行速度就越快(hertz, Hz) 比较的前提条件是,两者相同设计的CPU。如果CPU不同,一般就让他们比较相同工作下的性能 逻辑运算AND 屏蔽(掩码),常常用于图像装换 位映射,(用1,来测试对应位置的数值是否存在) OR 同样可以做到AND的用法 XOR 用于反转,如反转颜色 循环位置运算和位移运算循环位移 顾名思义 逻辑位移 空出的位置使用0 保留符号位的位移成为算数位移 设备通信 通过控制器作为中间层来完成通信 USB (Intel公司研发)/FireWire (Apple公司研发)等接口 DMA 直接存储器存取","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"数据存储","slug":"计算机科学概论/第一章、数据存储","date":"2018-05-31T14:16:34.000Z","updated":"2018-07-11T06:09:47.000Z","comments":true,"path":"2018/05/31/计算机科学概论/第一章、数据存储/","link":"","permalink":"https://ilifexiao.github.io/2018/05/31/计算机科学概论/第一章、数据存储/","excerpt":"","text":"第一章、数据存储keyword: 位存储(bit) Boole 运算 门电路 数字电路的设计过程,是极端几工程领域的一个重要课题 触发器(flip-fiop)是计算机存储器的基本部件,是现代计算机中存储二进制位的一种方法 1.2 主存储器(main memory) 包含大量的电路(触发器)每一个电路能够存储一个位,常被称为RAM 由称为存储单元(cell)的可管理单位组成 存储单元 独立的、可编址的存储单元 一个典型存储单元的容量为(8 bit)= 1byte 通过唯一标识符来表示每一个存储单元的地址 尽管触发器是存储二进制的一种方法 现代的计算机都是用其他类似的更复杂的技术制造的 为了压缩体积、提高响应速度 存为快速可消散的电荷,需要附加电路(称为刷新电路) 因其的不稳定性,所以成为DRAM(dynamic RAM) 存储器容量的度量 主存储器中的存储单元的总数通常为2的幂,因为设计起来比较方便 所以存在kilo表示的其实是1024,其他领域表示的是1000 海量存储技术 磁盘 光盘(compact disk),蓝光光碟的容量是DVD的5倍多 闪存驱动器 电子信号直接发送到存储介质中的,是介质中的二氧化硅的微小的晶格截获电子,能够在没有外力的情况下保存很多年 所以长期保存不入光学盘片可靠 较大的闪存驱动器称为固态硬盘(solid-state disk SSD),通过损耗均衡技术提高寿命 SD(secure card)卡 数值的表示 当记录的信息只有数值的时候,采用二进制、而不是字符编码(占用更多的空间) 16位二进制可表示0~65535 二进制补码、浮点计数法 (用于表示小数) 二进制通过(取反+1)获得负数 余码系统和二进制补码系统的区别就是符号位相反 每一个模式的二进制的值都比余码计数法大8(如:1000表示0,二进制表示8) 图像的表示 将图像解释为一组点(像素点),然后对每个像素进行编码——位图(bit map) 比如打印机、显示器等都是基于像素概念来操作的 对于更加精细的图片来说,每一个像素包含一组位(通常是8个) 矢量图 (记录几何结构、在放大的时候不会失真) 声音的表示 按照有规律的实践间隔来记录采集的振幅,并记录数值 远程电话通常使用8000/s次的采样频率,然后接收端重现 CD使用44100/s次的才上频率(用16位的形式表示,32位用于立体声) 压缩 分为无损压缩(lossless),有损压缩(lossy) 文本、图片、音频、视频压缩 通信差错 奇偶校验位 校验和、循环冗余校验 纠错码(汉明距离表示两个模式之间不同位的个数)","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"计算机科学概论","slug":"计算机科学概论","permalink":"https://ilifexiao.github.io/tags/计算机科学概论/"}]},{"title":"Hello World","slug":"Hello-World","date":"2018-05-18T12:48:01.000Z","updated":"2018-05-19T05:40:49.000Z","comments":true,"path":"2018/05/18/Hello-World/","link":"","permalink":"https://ilifexiao.github.io/2018/05/18/Hello-World/","excerpt":"","text":"介绍 通过Github Page 和 Hexo来搭建博客 Hexo,可以将markdown文件,结合主题自动转换成为网页(网页存放在public文件夹) 注意 github仓库的名字必须是:yourName.github.io,必须以你的帐号名称开头,github.io结尾才行 准备 按照Hexo安装步骤安装下列软件依赖,详细查看(https://hexo.io/zh-cn/docs/) Node.js Git(需要配置你的GitHub帐号,详细步骤可以搜索) Hexo 注意 没有文章的时候,将会导致网址不可访问 设置主题 选择一个你喜欢的主题下载到/yourSitePath/themes/xxx 1$ git clone https://github.com/WongMinHo/hexo-theme-miho.git themes/miho 修改主题的配置文件themes/xxx/_cnofig.yml,详细配置(https://blog.minhow.com/2017/08/01/blog/installation-configuration/) 一般上在这里设置网站的标题、描述、图片、菜单路径等 网站配置 https://hexo.io/zh-cn/docs/configuration.html 发布文章 下面展示如何通过命令行来发布文章 12345678# 会通过模板文件(默认:/scaffolds/post.md)来设置文章$ hexo new [layout] <title> # 清除网站的缓存,因为有可能删除了一些页面$ hexo clean# 重新生成$ hexo generate 如果自己已有md文件,那么直接放入source/_post,然后在文档的头部加入如下信息,更具实际情况修改 1234567title: Hello Worldcategories: Freetags: - mindcover_picture: images/default.jpegdate: 2018-05-18 20:48:01--- 注意 通过模板来发布文章,如果设置了post_asset_folder: true,那么对应的文章引用图片如果放在了对应文章的文件夹里,那么图片的引用地址需要加上日期,cover_picture:2018/05/18/Hello-World/hello.jpeg,因为文章是按照日期来分类的 新建页面12345678# 通过模板文件(默认:/scaffolds/page.md) source下新增一个xxx目录$ hexo new page \"xxx\"# 清除网站的缓存,因为有可能删除了一些页面$ hexo clean# 重新生成,然后可以看到public里出现了xxx的文件夹,所有的md,都会转换为对应的静态页面$ hexo generate 资源文件 图片、js文件等 存放路径 /source下,比如需要创建一个存放图片的文件/images,通过images/xx.png就可以引用了 自动部署 当你配置好网站后,就可以直接推送到github上面了 设置/_config.yml里的deploy关键字 1234deploy: type: git repository: https://github.com/iLifexiao/ilife.github.io.git branch: master 推送 1$ hexo deploy 这样就会把.deploy文件夹上传到仓库里,通过 https://ilife.github.io 就可以直接访问了 查看自己的仓库ls -a,就可以看到隐藏文件(以点号开头的名字)","categories":[{"name":"Free","slug":"Free","permalink":"https://ilifexiao.github.io/categories/Free/"}],"tags":[{"name":"mind","slug":"mind","permalink":"https://ilifexiao.github.io/tags/mind/"}]},{"title":"代码的坏味道","slug":"重构改善既有代码的设计/代码的坏味道","date":"2018-05-02T04:46:49.000Z","updated":"2018-07-11T06:04:41.000Z","comments":true,"path":"2018/05/02/重构改善既有代码的设计/代码的坏味道/","link":"","permalink":"https://ilifexiao.github.io/2018/05/02/重构改善既有代码的设计/代码的坏味道/","excerpt":"","text":"第三章、代码的坏味道 培养出自己的判断力——能够清晰地表达自己的观点 目的:清晰、容易理解、易于修改的代码 3.1 重复代码(Duplicated Code)方法: 提炼函数(Extract Method)P110 函数上移(Pull Up Method)P322 塑造模板函数(From Template Method)P345 替换算法(Substitute Algorithm)P139 提炼类(Extract Class)P149 含义: 你有一段代码可以被组织再一起并独立起来——将这段代码放进一个独立函数中,并让函数名称解释该函数的作用 有些函数再各个子类中产生完全相同的结果——将该函数移至超类 你有一些子类,期中相应的某些函数以相同的顺序执行类似的操作,但各个操作再细节上有所不同——将这些操作分别放进独立函数中,并保持他们有相同的签名,于是原函数也就变得相同了。然后将原函数移至超类 你想要把某个算法替换为另一个更清晰的算法——将函数本体替换为另一个算法 某个类做了应该由两个类做的事——建立一个新类,将相关字段和函数从旧类搬移到新类 阅读: 提炼函数(Extract Method) 将两个函数相同的部分提取出来(相同的部分可以是:代码、流程等) 函数上移(Pull Up Method) 将子类中做相同事情的函数,提升为超类中的方法 塑造模板函数(From Template Method) 也是对于子类中大部分相同的方法,提取出共有流程,然后不同的细节由子类的提取方法来完成 替换算法(Substitute Algorithm) 做相同的事情的代码一般上都会更简单的算法来实现 提炼类(Extract Class) 一个类应该是明确的抽象,处理一些明确的责任。是改善并发的常用技术,因为可以为两个类分别加锁 问题 解决 备注 同一个类的两个函数含有相同的表达式 1 两个子类含有相同的表达式 1,2 两个子类含有相似的表达,逻辑过程相同 1,2,3 函数以不同的算法,做相同的事情 4 毫不相关的类出现Duplicated Code 5 或第三方类(util.class) 3.2 长函数(Long Method) 函数式编程、利用所有的代码段组合,来完成大型的特定功能 解释: “间接层”所能带来的全部利益——解释能力、共享能力、选择能力——都是由小型函数支持的P61 让小函数容易理解的真正关键在于一个好的名字,这样就可以免去返回查看其他函数做了什么 最终效果:应该积极的分解函数 原则:每当感觉需要注释来说明点什么东西,就吧需要说明的东西移动到独立函数里,并以其用途(而非实现手法)命名 注释的对象:一行、一组代码,哪怕替换后的函数调用动作比自身函数还长,只要函数名称能够解释其用途即可。关键不在于函数的长度,而在于函数“做什么”和“如何做”之间的语义距离 99%的场合里,只要提炼方法即可 如果函数里面有大量的参数和临时变量, 方法: 提炼函数(Extract Method)P110 以查询代替临时变量值(Replace temp with Query)P120 引入参数对象(Introduce Parameter Object)P295 保持对象完整(Preserve Whole Object)P288 以函数对象取代函数(Replace Method with Method Object)P135 分解条件表达式(Decompose Conditional)P238 含义: 你有一段代码可以被组织再一起并独立起来——将这段代码放进一个独立函数中,并让函数名称解释该函数的作用 你的程序以一个临时变量保存某一表达式的运算结果——将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对新函数的调用,此后,新函数就可以被其他函数使用 某些参数总是很自然地同时出现——以一个对象取代这些参数 你从某个对象中取出若干值,将他们作为某一次函数调用时的参数——改为传递整个对象 你有一个大型函数,其中对局部变量的使用使你无法采用Extract Method——将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后你可以再同一个对象中将这个大型函数分解为多个小型函数 你有一个复杂的条件(if-then-else)语句——从if、then、else三个段落分别提炼出独立函数 阅读: 提炼函数(Extract Method) 将两个函数相同的部分提取出来(相同的部分可以是:代码、流程等) 以查询代替临时变量值(Replace temp with Query) 临时变量的问题在于它是局部的,所以会让你写出更长的函数 如果把它替换为一个查询函数,那没在该类所有的方法都可以访问到该变量信息。 但有时难以提炼(临时变量被多次赋值等),可以尝试用分解临时变量(Split Temporary Variable)或将查询函数和修改函数分离(Sperate Qurey form Modifer)使情况变得简单一些,然后再替换临时变量 引入参数对象(Introduce Parameter Object) 对于数据泥团(Data Clumps),可以运用对象包装这些数据。 然后也可以发现可以移动到新类中的通用方法(常常是对包装的数据处理代码段),这样就进一步地降低了代码的理解和修改难度 保持对象完整(Preserve Whole Object) 原因在于:万一函数将来需要新的数据项,就需要修改所有的调用处 而对象则可以简单的增加信息,函数就能获取到新的数据项,而不修改方法参数。如果这样会使得你的代码结构恶化,那就不要使用该方法 对于函数只传递对象的期中一项数据,那么只传递数值还是传递对象? 也许传递对象会有一点的性能问题,但是更重要的在于对象之间的依赖关系 如果被调用的函数使用了来自另一个对象的很多项数据,这可能意味着该函数应该被定义在那些数据所属的对象中,即需要考虑搬移函数(Move Method) 以函数对象取代函数(Replace Method with Method Object) 对于大量存在的局部变量,会导致难以分解一个大型函数 建立一个新类,根据待处理函数的用途,为这个类命名,字段为那些临时变量 创建构造函数,comput()用于处理需提取的函数,然后引用该函数的调用对象,用于访问调用对象的的值 分解条件表达式(Decompose Conditional) 复杂的条件逻辑是最常导致复杂度上升的地点之一 对于嵌套的条件表达式:以卫语句取代嵌套条件表达式(Replalce Nested Conditional with Guard Clauses) 同样也是再拉近代码和语义解释之间的距离 问题 解决 备注 每当需要通过注释来解释说明的时候 1 函数中有单一且唯一赋值的临时变量 2 调用函数的参数过多或临时变量很多 3,4 调用函数的参数和临时变量都很多 5 函数里碰到复杂的条件表达式和循环 6 3.3 过大的类(Larger Class)解释: 利用单个类做太多的事情,导致出现太多的实例变量 同样会出现许多的重复函数 方法: 提炼类(Extract Class)P149 提炼子类(Extract Subclass)P330 提炼接口(Extract Interface)P341 含义: 某个类做了应该由两个类做的事——建立一个新类,将相关字段和函数从旧类搬移到新类 类中的某些特性只被某些(并非全部)实例用到——新建一个子类,将上诉的那一部分特性移到子类中 若干客户使用类接口中的同一子集,或者两个类的接口有部分相同——将相同的子集提炼到一个独立的接口中 阅读: 提炼类(Extract Class) 一个类应该是明确的抽象,处理一些明确的责任。是改善并发的常用技术,因为可以为两个类分别加锁 提炼子类(Extract Subclass) 与提炼类(Extract Class)相比,先处理函数再处理数据会更简单一点 提炼接口(Extract Interface) 对于使用到类中的一部分功能,可以考虑将其划分到接口中 这样可以使得程序调用更加地清晰,以及将来可以接入更多的功能,只有实现了该接口即可 和提炼超类(Extract Superclass)有相似之处,他只能提炼公共接口,不能提供通用代码 可能会导致重复代码,可以使用提炼类(Extract Class)将通用行为,放到组件里面,然后委托该类执行 还有一种用法是,用接口来表示外部服务 3.4 过长参数列(Long Parameter List)解释: 导致难以理解 后期添加新的数据,会导致需要修改太多地方 方法: 用函数代替参数(Replace Parameter with Method)P292 保持对象完整(Preserve Whole Object)P288 引入参数对象(Introduce Parameter Object)P295 含义: 对象调用某个函数,并将所得的结果作为参数,传递给另一个函数,而接受该参数的函数本身也能调用前一个函数——让参数接收者去除该项参数,并直接调用前一个函数 你从某个对象中取出若干值,将他们作为某一次函数调用时的参数——改为传递整个对象 某些参数总是很自然地同时出现——以一个对象取代这些参数 阅读: 用函数代替参数(Replace Parameter with Method) 办法一:看看接收端是否能和调用端采用相同的计算来获取到参数值 以明确的函数取代参数(Replace Parameter with Explicit Methods) P285 以上如,工程方法的调用根据不同的类型创建不同的对象 为了以后接口的灵活,而预留的多余参数:可以预算一下修改的成本 & 是否需要降低各个部位之间的依赖 保持对象完整(Preserve Whole Object) 原因在于:万一函数将来需要新的数据项,就需要修改所有的调用处 而对象则可以简单的增加信息,函数就能获取到新的数据项,而不修改方法参数。如果这样会使得你的代码结构恶化,那就不要使用该方法 对于函数只传递对象的期中一项数据,那么只传递数值还是传递对象? 也许传递对象会有一点的性能问题,但是更重要的在于对象之间的依赖关系 如果被调用的函数使用了来自另一个对象的很多项数据,这可能意味着该函数应该被定义在那些数据所属的对象中,即需要考虑搬移函数(Move Method) 引入参数对象(Introduce Parameter Object) 对于数据泥团(Data Clumps),可以运用对象包装这些数据。 然后也可以发现可以移动到新类中的通用方法(常常是对包装的数据处理代码段),这样就进一步地降低了代码的理解和修改难度 3.5 发散式变化(Divergent Change)解释: “一个类受多种变化的影响” 我们希望的是,一个类受到的影响尽量只有一种 方法: 提炼类(Extract Class)P149 含义: 类中的某些特性只被某些(并非全部)实例用到——新建一个子类,将上诉的那一部分特性移到子类中 阅读: 提炼类(Extract Class) 一个类应该是明确的抽象,处理一些明确的责任。是改善并发的常用技术,因为可以为两个类分别加锁 3.6 散弹式修改(Shotgun Surgery)解释: 类似Divergent Change,但也可以看做类的联系较为耦合,修改时需要修改这些因为外部状态改变下的方法 “表示一种变化引发多个类相应修改” 常常我们希望“外界变化”与“需要修改的类”趋于一一对应 方法: 搬移函数(Move Method)P142 搬移字段(Move Field)P146 将类内联化(Inline Class)P154 含义: 你的程序中,有个函数与其所在的类之外的类进行更多的交流(往往是因为另一个类的数据):调用后者,或者被前者调用——在该函数最常引用的类中建立一个与该方法行为类似的新函数。将旧函数编程一个单纯的委托函数,或者完全移除旧函数 再你的程序中,某个字段被其所在的类之外的类更多的使用——再目标类新建一个字段,修改源字段的所有用户,令它们改用新字段 某个类没有做太多事情——将这个类的所有特性搬移到另一个类中,然后移除原类 阅读: 搬移函数(Move Method) “搬移函数”是重构理论的支柱 对于该函数如果引用了源类的函数,需要考虑将源类作为参数传递给方法 搬移字段(Move Field) 再类之间移动状态和行为,是重构之中不可缺少的部分 再使用Extract Class时,通常先搬移字段,后搬移函数 对于该类中的许多函数都用到了该字段,采用Self Encapsulate Field,这样只有修改访问函数即可 将类内联化(Inline Class) 正好与Extract Class相反,如果一个类不在承担足够的责任,不在有单独存在的理由 3.7 依恋情节(Feature Envy)解释: 对象技术的要点:“将数据和对数据的操作行为包装在一起” 对于一个函数用到多个类的情况下,判断哪个类拥有最多被此函数使用的数据,就搬移到那个类中 对于上诉的函数,先采用Extract Class会比较容易一些 方法: 提炼函数(Extract Method)P110 搬移函数(Move Method)P142 含义: 你有一段代码可以被组织再一起并独立起来——将这段代码放进一个独立函数中,并让函数名称解释该函数的作用 你的程序中,有个函数与其所在的类之外的类进行更多的交流(往往是因为另一个类的数据):调用后者,或者被前者调用——在该函数最常引用的类中建立一个与该方法行为类似的新函数。将旧函数编程一个单纯的委托函数,或者完全移除旧函数 阅读: 提炼函数(Extract Method) 将两个函数相同的部分提取出来(相同的部分可以是:代码、流程等) 搬移函数(Move Method) “搬移函数”是重构理论的支柱 对于该函数如果引用了源类的函数,需要考虑将源类作为参数传递给方法 3.8 数据泥团(Data Clump)解释: 两个类中相同的字段、函数的相同参数 这些总是出现再一起的数据应该拥有他们自己的对象 这样做可以缩短参数列表,简化函数的调用 方法: 提炼类(Extract Class)P149 引入参数对象(Introduce Parameter Object)P295 保持对象完整(Preserve Whole Object)P288 含义: 类中的某些特性只被某些(并非全部)实例用到——新建一个子类,将上诉的那一部分特性移到子类中 某些参数总是很自然地同时出现——以一个对象取代这些参数 你从某个对象中取出若干值,将他们作为某一次函数调用时的参数——改为传递整个对象 阅读: 提炼类(Extract Class) 一个类应该是明确的抽象,处理一些明确的责任。是改善并发的常用技术,因为可以为两个类分别加锁 引入参数对象(Introduce Parameter Object) 对于数据泥团(Data Clumps),可以运用对象包装这些数据。 然后也可以发现可以移动到新类中的通用方法(常常是对包装的数据处理代码段),这样就进一步地降低了代码的理解和修改难度 保持对象完整(Preserve Whole Object) 原因在于:万一函数将来需要新的数据项,就需要修改所有的调用处 而对象则可以简单的增加信息,函数就能获取到新的数据项,而不修改方法参数。如果这样会使得你的代码结构恶化,那就不要使用该方法 对于函数只传递对象的期中一项数据,那么只传递数值还是传递对象? 也许传递对象会有一点的性能问题,但是更重要的在于对象之间的依赖关系 如果被调用的函数使用了来自另一个对象的很多项数据,这可能意味着该函数应该被定义在那些数据所属的对象中,即需要考虑搬移函数(Move Method) 3.9 基本类型偏执(Primitive Obsession)解释: 大多数编程环境都允许将数据组织成有意义的形式,结构体、类等 对象的一个极大价值在于:他们模糊了基本数据类型和体积较大的类之间的界限? 例如:以类String、Date表示字符串和日期类,进而进入对象编程的世界 方法: 以对象取代数据项(Replace Data Value with Object)P175 以类取代类型码(Replace Type Code with Class)P218 以子类取代类型码(Replace Type Code with Subclasses)P223 以State/Strategy取代类型码(Replace Type Code with State/Strategy)P227 提炼类(Extract Class)P149 引入参数对象(Introduce Parameter Object)P295 以对象取代数组(Replace Array with Object )P186 含义: 你有一个数据项,需要与其他数据和行动为一起使用才有意义——将数据项编程对象 类之中有一个数值类型码,但它并不影响类的行为——以一个新的类替换该数值类型码 你有一个不可变的类型码,它会影响子类的行为——以子类取代这个类型码 你有一个类型码,它会影响类的行为,但你无法通过继承手法消除它——以状态对象取代类型码 类中的某些特性只被某些(并非全部)实例用到——新建一个子类,将上诉的那一部分特性移到子类中 某些参数总是很自然地同时出现——以一个对象取代这些参数 你有一个数组,其中的元素各自代表不同的东西——以对象代替数组。对于数组中的每个元素,以一个字段来表示 阅读: 以对象取代数据项(Replace Data Value with Object) 开发初期,使用简单的数据来表示简单的情况。后期可能发现需要改变的东西比较多,情况变得复杂起来 以类取代类型码(Replace Type Code with Class) 提高代码的可读性,能够提供运行期检测 为类型类提供工厂函数,这样九可以确保正确的和法的对象呗创建出来 只有当类型码是纯粹数据时(就是类型码不会在switch语句中引起行为变化),你才能以类取代他 还需注意类型码不会因其数值不同而引起行为上的差异,宿主中的某些行为还是可以移动到类型中的 以子类取代类型码(Replace Type Code with Subclasses) 以类型码的宿主为基类,针对每一种类型建立相应的子类 其主要作用是为了让Replace Conditional with Polymorphism得以实现,否则使用Replace Type Code with Class较为合适,风险也更将低 还有一个原因是为了,将宿主类中的只于特定类型有关的属性或者方法移动到合适的子类中去 这对未来新添加的行为更容易 以State/Strategy取代类型码(Replace Type Code with State/Strategy) 和Replace Type Code with Subclasses很相似,但是如果类型码的值在对象的生命周期里发生了变化或者其他原因使得宿主类不能被继承 类型码的值在对象的生命周期里发生了变化:这里可以引入一个中间层来完成转换,使它成为一个属性 本重构使用State或Strategy模式,这两个模式非常相似,无论选择哪一个重构的过程都是相同的 如果打算完成本项重构后使用Replace Conditional with Polymorphism,那么使用Strategy模式比较合适;如果打算搬移与状态相关的数据,而且把新建的对象视为一种变迁状态,那么使用State模式 提炼类(Extract Class) 一个类应该是明确的抽象,处理一些明确的责任。是改善并发的常用技术,因为可以为两个类分别加锁 引入参数对象(Introduce Parameter Object) 对于数据泥团(Data Clumps),可以运用对象包装这些数据。 然后也可以发现可以移动到新类中的通用方法(常常是对包装的数据处理代码段),这样就进一步地降低了代码的理解和修改难度 以对象取代数组(Replace Array with Object ) 数组常用于容纳一组相似的对象,当用于存放不同的对象时,会导致难以记住顺序 通过设置类来完成意义化语义 问题 解决 备注 小任务上的对象(类似money、range、zipcode) 1 不影响行为的类型码 2 与类型码相关的条件表达式 3、4 一组应该总是被放在一起的字段 5 再参数列表中看到基本类型 6 发现自己正从数组中挑选数据 7 3.10 switch惊悚现身(Switch Statements)解释: 面向对象程序的一个最明显特征:少用switch或(case)语句,从本质上说,switch语句的问题在于重复,经常会发现同样的switch语句散部在不同的地点,如果要添加新的case语句就要找到所有的switch语句并修改它们 大多数时候,一看到switch语句,就应该使用多态来代替他,但是对象单一函数中有些选择事例,且并不想改动它们,那么使用多态就显得杀鸡用牛刀,这时候使用Replace parameter with Explicit Methods 就不错 当然也可以使用再if-else语句中 方法: 提炼函数(Extract Method)P110 搬移函数(Move Method)P142 以子类取代类型码(Replace Type Code with Subclasses)P223 以State/Strategy取代类型码(Replace Type Code with State/Strategy)P227 以多态取代条件表达式(Replace Conditional with Polymorphism)P255 以明确函数取代参数(Replace Parameter with Explicit Methods) P285 引入 Null 对象(Introduce Null Object)P260 含义: 你有一段代码可以被组织再一起并独立起来——将这段代码放进一个独立函数中,并让函数名称解释该函数的作用 你的程序中,有个函数与其所在的类之外的类进行更多的交流(往往是因为另一个类的数据):调用后者,或者被前者调用——在该函数最常引用的类中建立一个与该方法行为类似的新函数。将旧函数编程一个单纯的委托函数,或者完全移除旧函数 你有一个不可变的类型码,它会影响子类的行为——以子类取代这个类型码 你有一个类型码,它会影响类的行为,但你无法通过继承手法消除它——以状态对象取代类型码 你手上有个条件表达式,它根据对象类型的不同而选择不同的行为——将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明稳抽象函数 你有一个函数,期中完全取决于参数值而采取不同行为——针对该参数的每一个可能值,建立一个独立函数 你需要再三检查某对象是否为null——将null值替换为null对象 阅读: 提炼函数(Extract Method) 将两个函数相同的部分提取出来(相同的部分可以是:代码、流程等) 搬移函数(Move Method) “搬移函数”是重构理论的支柱 对于该函数如果引用了源类的函数,需要考虑将源类作为参数传递给方法 以子类取代类型码(Replace Type Code with Subclasses) 以类型码的宿主为基类,针对每一种类型建立相应的子类 其主要作用是为了让Replace Conditional with Polymorphism得以实现,否则使用Replace Type Code with Class较为合适,风险也更将低 还有一个原因是为了,将宿主类中的只于特定类型有关的属性或者方法移动到合适的子类中去 这对未来新添加的行为更容易 以State/Strategy取代类型码(Replace Type Code with State/Strategy) 和Replace Type Code with Subclasses很相似,但是如果类型码的值在对象的生命周期里发生了变化或者其他原因使得宿主类不能被继承 类型码的值在对象的生命周期里发生了变化:这里可以引入一个中间层来完成转换,使它成为一个属性 本重构使用State或Strategy模式,这两个模式非常相似,无论选择哪一个重构的过程都是相同的 如果打算完成本项重构后使用Replace Conditional with Polymorphism,那么使用Strategy模式比较合适;如果打算搬移与状态相关的数据,而且把新建的对象视为一种变迁状态,那么使用State模式 以多态取代条件表达式(Replace Conditional with Polymorphism) 如果需要改用多态,只需建立一个新的子类,并再其中提供适当的函数 类的用户不需要了解这个子类,这就大大降低了系统各部分之间的依赖,使系统升级更加容易 也就是把对应类型case语句中的操作移动到子类当中去 以明确函数取代参数(Replace Parameter with Explicit Methods) 可以使得接口变得更加清晰,和获得编译期检查 也避免了检查所给的参数是否合格 引入 Null 对象(Introduce Null Object) 为了减少重复判断某个数值是否为空,往往需要大量的过程代码 使用空对象可以带来:减少重复的过程代码、可以像正常对象一样显示、不会破坏系统(设置和普通对象一样的方法&特殊的返回值) 但是存在一个问题是:有时会造成问题的侦查和查找上的困难 重要的一点:空对象一定是一个常量,他们的任何成分都不应该发生变化,所以采用单例模式比较合适 需要的是大多数客户代码都对空对象做出了相同的相应,其他不同的依然可以使用isNull()函数 经常会看到空对象返回了其他的空对象,对于空对象调用了其他类的方法,同样可以制造空的对象(通过继承来完成) 可以通过建立一个接口,来使得不能修改的类使用null对象 Special Cas:特例的价值,可以降低你错误处理的开销 问题 方法 备注 switch语句 1、2、3、4、5 按顺序 单一函数中的switch语句 6 选择条件之一是null 7 3.11 平行继承体系(Parallel Inheritance Hierarchies)解释: parallel inheritance hierarchies 是 Shotgun Surgery的特殊情况 在这种情况下,每当你为一个类添加一个新的子类,就必须要为另一个类添加一个子类 如果看到某个继承体系的类名称前缀和另一个继承体系的完全相同,便是这种问题 消除这种问题的一般策略是:让另一个继承体系的实例引用另一个继承体系的实例 方法: 搬移函数(Move Method)P142 搬移字段(Move Field)P146 含义: 你的程序中,有个函数与其所在的类之外的类进行更多的交流(往往是因为另一个类的数据):调用后者,或者被前者调用——在该函数最常引用的类中建立一个与该方法行为类似的新函数。将旧函数编程一个单纯的委托函数,或者完全移除旧函数 在你的程序中,某个字段被其所在的类之外的类更多的使用——再目标类新建一个字段,修改源字段的所有用户,令它们改用新字段 阅读: 搬移函数(Move Method) “搬移函数”是重构理论的支柱 对于该函数如果引用了源类的函数,需要考虑将源类作为参数传递给方法 搬移字段(Move Field) 再类之间移动状态和行为,是重构之中不可缺少的部分 再使用Extract Class时,通常先搬移字段,后搬移函数 对于该类中的许多函数都用到了该字段,采用Self Encapsulate Field,这样只有修改访问函数即可 3.12 冗赘类(Lazy Class)解释: 每一个类都需要人,来维护,来理解 对于哪些做工作较少,和不在使用的类,把他们从代码中删除 方法: 折叠继承体系(Collapse Hierarchy)P344 将类内联化(Inline Class)P154 含义: 超类和子类之间无太大的区别——将他们合为一体 再你的程序中,某个字段被其所在的类之外的类更多的使用——再目标类新建一个字段,修改源字段的所有用户,令它们改用新字段 阅读: 折叠继承体系(Collapse Hierarchy) 对于没有带来价值的类,把它和子类合并起来 将类内联化(Inline Class) 正好与Extract Class相反,如果一个类不在承担足够的责任,不在有单独存在的理由 3.13 夸夸其谈未来性(Speculative Generality )解释: 对未来可能出现的事物,事先完成 或者某个函数或者类的唯一用户是测试用例,那么就把他们连同测试用例一起删除 如果他们的用途是帮助用力检测正当的功能,可以留下 方法: 折叠继承体系(Collapse Hierarchy)P344 将类内联化(Inline Class)P154 移除参数(Remove Parameter )P277 函数改名(Rename Method)P273 含义: 超类和子类之间无太大的区别——将他们合为一体 再你的程序中,某个字段被其所在的类之外的类更多的使用——再目标类新建一个字段,修改源字段的所有用户,令它们改用新字段 函数本体不在需要某个参数——将该参数去除 函数名称未能揭示函数的用途——修改函数名称 阅读: 折叠继承体系(Collapse Hierarchy) 对于没有带来价值的类,把它和子类合并起来 将类内联化(Inline Class) 正好与Extract Class相反,如果一个类不在承担足够的责任,不在有单独存在的理由 移除参数(Remove Parameter ) 对于多态,就需特殊考虑了。因为某个参数可能需要再另一个状态里使用 函数改名(Rename Method) 将复杂的处理过程分解成小函数,所以需要设置好小函数的名称,代码首先是为了人写的,其次才是计算机 可以先暂时使用新函数调用旧函数,来保证小步前进 3.14 令人迷惑的暂时字段(Temporary Field)解释: 对象内的某个实例变量仅为某种特定情况而设,这样的代码会让人不易理解 在一个类中有一个复杂的算法,需要使用到好几个变量来完成,为了避免使用过长的参数列表,则使用字段来表示。但是这些变量只在这个算法里使用,所以使用Extract Class比较好,使之变成一个函数对象 方法: 提炼类(Extract Class)P149 含义: 某个类做了应该由两个类做的事——建立一个新类,将相关字段和函数从旧类搬移到新类 阅读: 提炼类(Extract Class) 一个类应该是明确的抽象,处理一些明确的责任。是改善并发的常用技术,因为可以为两个类分别加锁 3.15 过度耦合的消息链(Message Chains)解释: 用户向一个对象请求另一个对象,然后后者又请求另一个对象,然后再请求另一个对象…….这就是消息链 这样的耦合度代码,使得一旦对象发生了任何关系上的变化,都会导致客户端不得不做出修改 并不是所有的函数链都是不好的,要根据实际情况分析 方法: 隐藏委托关系(Hide Delegate)P157 含义: 客户通过一个委托类来调用另一个对象——再服务类上建立客户所需要的所有函数,用以隐藏委托关系 阅读: 隐藏委托关系(Hide Delegate) 封装是对象的最关键特征之一,意味着每个对象都应该尽可能少了解系统的其他部分,这样一来,一旦发生变化,需要了解这一变化的对象就比较少 可以随时取消这一层委托(Client->Server->Delegate) 3.16 中间人(Middle Man)解释: 对象的基本特征之一就是封装——对外部世界隐藏其内部细节 人们也许会过度使用委托,可能看到某个类的接口有一半的函数都委托了给其他类,可以采用Inline Method 如果中间人还有更多的行为,可以使用Replace Delegate with Inheritance 方法: 移除中间人(Remove Middle Man)P160 内联函数(Inline Method)P117 以继承取代委托(Replace Delegate with Inheritance)P355 含义: 某个类做了过多的简单委托动作——让客户直接调用受托类 一个函数的本体与名称一样清楚易懂——在函数调用点插入函数本体,然后移除该函数 你在两个类之间使用委托关系,并经常为整个接口编写许多极简单的委托函数——让委托类继承受托类 阅读: 移除中间人(Remove Middle Man) 这个是Hide Delegate的相反过程,临界点在于是否过度委托,当然把握这个临界点是比较难说的 但也不用在意临界点,只要不断重构就好了 内联函数(Inline Method) 这和Extract Method是一个相反的过程,核心在于程序是否清晰易读,是否重复等 使用该方法的情况二:你手上有一群组织不合理的函数,你可以把它们都内联到一个大型函数中,再从中提取组织合理的小函数 使用该方法的情况三:对于使用了太多间接层,使得系统中的函数几乎都是对另一个函数的调用 以继承取代委托(Replace Delegate with Inheritance) 和Replace Inheritance with Delegate 刚好相反,对于的是编写简单的方法(类似调用等) 注意两点:一是如果没有使用受托类的全部方法,就不应该执行此重构,因为子类总是遵循超类的接口;二是受托被对象不止一个其他对象共享,而且受托对象是可变的,因为这样就无法在共享数据了。数据共享必须是委托关系承当的一种责任,你无法把它转给继承关系。 3.17 狎昵关系(Inappropriate Intimacy)解释: 两个类过分地探究互相的私有成分 方法: 搬移函数(Move Method)P142 搬移字段(Move Field)P146 将双向关联改为单向关联(Change Bidirectional Association to Unidirectional)P200 提炼类(Extract Class)P149 含义: 你的程序中,有个函数与其所在的类之外的类进行更多的交流(往往是因为另一个类的数据):调用后者,或者被前者调用——在该函数最常引用的类中建立一个与该方法行为类似的新函数。将旧函数编程一个单纯的委托函数,或者完全移除旧函数 在你的程序中,某个字段被其所在的类之外的类更多的使用——再目标类新建一个字段,修改源字段的所有用户,令它们改用新字段 两个类之间有双向关联,但期中一个类如今不在需要另一个类的特性——去除不必要的关联 某个类做了应该由两个类做的事——建立一个新类,将相关字段和函数从旧类搬移到新类 阅读: 搬移函数(Move Method) “搬移函数”是重构理论的支柱 对于该函数如果引用了源类的函数,需要考虑将源类作为参数传递给方法 搬移字段(Move Field) 再类之间移动状态和行为,是重构之中不可缺少的部分 再使用Extract Class时,通常先搬移字段,后搬移函数 对于该类中的许多函数都用到了该字段,采用Self Encapsulate Field,这样只有修改访问函数即可 将双向关联改为单向关联(Change Bidirectional Association to Unidirectional) 容易导致循环引用 导致系统之间过于耦合,任何一个改动可能导致牵一发而动全身 提炼类(Extract Class) 一个类应该是明确的抽象,处理一些明确的责任。是改善并发的常用技术,因为可以为两个类分别加锁 3.18异曲同工的类(Alternative Classes with Different Interface)解释: 两个函数做同一件事,却有着不同的函数签名,根据用途使用Rename Method 可以反复使用Move Method将某些行为移入类,直到两者协议一致 方法: 搬移函数(Move Method)P142 提炼超类(Extract Superclass)P336 含义: 你的程序中,有个函数与其所在的类之外的类进行更多的交流(往往是因为另一个类的数据):调用后者,或者被前者调用——在该函数最常引用的类中建立一个与该方法行为类似的新函数。将旧函数编程一个单纯的委托函数,或者完全移除旧函数 两个类有相似的特性——为这两个类建立一个超类,将相同的特性移至超类 阅读: 搬移函数(Move Method) “搬移函数”是重构理论的支柱 对于该函数如果引用了源类的函数,需要考虑将源类作为参数传递给方法 提炼超类(Extract Superclass) 减少重复代码,在发现两个类的通性就可以考虑提炼超类 3.19 不完美的库类(Incomplete Library Class)解释: 复用常被视为对象的终极目的,不过我们认为,复用的意义经常被高估 所以对于想修改库类的一些方法,或者添加一些方法(ios中的类别) 方法: 引入外加函数(Introduce Foreign Method)P162 引入本地扩展(Introduce Local Extension)P164 含义: 你需要为你提供服务的类增加一个函数,但你无法修改这个类——在客户类中建立一个函数,并以第一参数形式传入一个服务类实例 你需要为服务类提供一些额外函数,但你无法修改这个类——建立一个新类,使它包含这些额外函数。让这个扩展品成为源类的子类或包装类 阅读: 引入外加函数(Introduce Foreign Method) 相当于扩展工具类的方法,相当于在进行了一次封装 引入本地扩展(Introduce Local Extension) 和Introdect Foreign Method类似,只是引入的方法数量大于等于两个或者需要大量引用该函数 本地扩展包是一个独立的类(类别) 可以选择子类hi或者包装类来完成工作,一般上推荐使用子类,因为可以向上兼容 3.20 幼稚的数据类(Data Class)解释: 就像数据容器,只有数据和数据的访问方法 所以可能会看到该类的被其他类控制着 对于集合的数据,使用Encapsulate Collection 不想让其他类修改的字段,使用Remove Seting Method 对于使用了这些取值函数或者设值函数,可以使用Move Method,将方法移动到该类中 方法: 封装字段(\u001dEncapsulate Field)P206 封装集合(Encapsulate Collection)P208 移除设值函数(Remove Seting Method)P300 隐藏函数(Hide Method)P303 含义: 你的类中存在一个Public字段——将它声明为private,并提供相应的访问函数 有个函数返回一个集合——让这个函数返回该集合的一个只读副本,并在这个类中提供添加、移除集合元素的函数 类中的某个字段应该在对象创建的时候被赋值,然后就不再改变——去掉该字段的所有设值函数 有一个函数没有被其他类用到——将这个函数修改为privete 阅读: 封装字段(\u001dEncapsulate Field) 面向对象的首要的原则之一就是封装,或者成为“数据隐藏” 封装集合(Encapsulate Collection) 一个类提供了集合(array/list/set等),采用和不同数据类型的封装方法 比如:push, pop等,避免用户修改整个集合的值 移除设值函数(Remove Seting Method) 将不可变字段设置为final 隐藏函数(Hide Method) 重构往往促使你修改函数的可见度 3.21 被拒绝的遗赠(Refused Bequest)解释: 对于继承来说,如果有不想要继承的数据或者方法,可以设计一个兄弟类,把用不到的方法和数据通过Push Down Method和Push Down Field移动到该类中 常常可以听到,所有的超类都应该是抽象的 如果子类复用超类的行为(实现),却不愿意支持超类的接口,就应该使用Replace Inheritance with Delegation 方法: 函数下移(Push Down Method)P328 字段下移(Push Down Field)P329 以委托取代继承(Replace Inheritance with Delegation)P352 含义: 超类中的某个函数只与部分(而非全部)子类有关——将这个函数移到相关的那些子类去 超类中的某个字段只被部分(而非全部)子类用到——将这个字段移到需要它的那些子类去 某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据——在子类中新建一个字段用以保存超类,调整子类函数,令它改而委托超类;然后渠道两者之间的继承关系 阅读: 函数下移(Push Down Method) 把某些行为从超类移至特定的子类 字段下移(Push Down Field) 把某些字段从超类移至特定的子类 以委托取代继承(Replace Inheritance with Delegation) 需要在该类宅保存委托类的对象(iOS, delegaet, weak) 3.22 过多的注释(Comments)解释: 如果你感觉需要注释的时候,请先尝试重构,试着让代码来解释 方法:含义:阅读:","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"重构","slug":"重构","permalink":"https://ilifexiao.github.io/tags/重构/"}]},{"title":"重构的原则","slug":"重构改善既有代码的设计/重构的原则","date":"2018-05-01T03:55:03.000Z","updated":"2018-07-11T06:05:19.000Z","comments":true,"path":"2018/05/01/重构改善既有代码的设计/重构的原则/","link":"","permalink":"https://ilifexiao.github.io/2018/05/01/重构改善既有代码的设计/重构的原则/","excerpt":"","text":"第二章、重构的原则2.1 何为重构名词定义: 对软件内部结构的一种调整,目的是在不改变软件壳观察行为的前提下,提高其壳理解性,降低其修改成本 动词定义: 使用一系列重构手法,在不改变软件壳观察行为的前提下,调整其结构 重构只是整理代码? 重构可以理解为整理代码,但它可以提供一种更高效且受控的代码整理技术 两顶帽子: 分为:添加新功能、重构 重构的时候就不要在添加新的功能了 2.2 为何重构1. 重构改进软件设计 如果没有重构,程序的设计会逐渐变得腐败变质。也就是说,代码的流失是累积性的 改进的一个重要方向就是消除重复代码(DRY) 2. 重构使软件更容易理解 代码的理解是面向人类的 作者对与那些能够立刻查阅的东西,大多都不刻意区记忆。往往在查询的过程中,你就逐渐地记住了 利用重构来理解不熟悉的代码 重构使得代码变得更加地清晰,可以让你发现一些以前看不到的设计层面的东西 3. 重构帮助找到BUG 也就是重构能够提高对代码的理解,也就能够发现原先代码的一些不足之处 优秀的习惯能够让你成为一个好程序员 4. 重构提高编程速度 重构帮助你更快速地开发程序 良好的设计是快速开发的根本,因为其降低了程序的修改成本和理解成本(在大型程序中往往更容易发现) 2.3 何时重构 重构不来九不是一件应该特别拨出时间来做的事情,重构应该随时进行 三次法则 重复三次做同样的事情,就应该着手重构 添加功能时重构 最常见的重构时机,就是添加新的功能的时候 即降低软件的修改成本,提高对代码的理解。在未来添加新的功能可以更加的容易和快速 修补错误时重构 调试的时候运用重构,多半是为了让代码更具有可读性 复审代码时重构 很多公司都会做常规的代码复审,因为这种活动可以改善开发的状况 让知识在开发团队里面传播,也能够想出更好的点子 重构一样可以帮助你复审别人的代码 在复审的时候,最好是复审者搭配一个原作者,也就是极限编程里面所说的“结对编程” 为什么重构有用? 程序有两面价值:“今天可以为你做什么”和“明天可以为你做什么” 重构也就是为未来软件的修改降低成本 程序难以相与的原因 难以阅读的程序,难以修改 逻辑重复的程序,难以修改 添加新的功能时,需要修改已有代码的程序,难以修改 带复杂条件逻辑的程序,难以修改 我们期望程序 容易阅读 所有逻辑都只在唯一地点指定 新的改动不会危及现有的行为 斤可能简单表达条件逻辑 2.4 怎么对经历说 对于懂技术的经历来说,解释重构应该不难 对于值关心质量的经理,那么问题九集中在了“质量”上面 大量研究结果表明,技术复审是减少错误、提高开发速度的一条重要的途径 或者在难以解释的情况下,不告诉可能比较好 间接层和重构 计算机科学是这样一门科学:他相信所有的问题都可以添加一个间接层来解决 但是间接层是一把双刃剑,每次把东西分成两份,你就要多管理一份东西,代理委托就回变得更加复杂 间接层的价值: 允许逻辑共享(重复函数) 分开解释意图和实现 隔离变化(比如子类,可以避免影响父类的操作(有两个地方调用了父类,我就可以考虑设计一个子类)) 封装条件逻辑(对象的奇妙机制:多态消息,可以清晰灵活地表达条件逻辑,将条件逻辑转换为消息形式,往往能够降低代码的重复、增加清晰度并提高弹性) 2.5 重构的难题 学习一种可以大幅度提高生产力的新技术时,你总是难以察觉其不适用的场合 在10年前,对象技术也往往如此。要反对那种盲目性 随着对重构的了解日益增多,我们也要监控那些重构可能引入的问题 数据库 重构经常出现的一个领域就是数据库,绝大多数的商用程序和数据库都是紧密地耦合在一起,数据库结构和对象模型紧密的结合在一起 还有一个问题就是数据库迁移(migration),数据结构的改变导致你需要迁移所有的数据 在非对象数据库中:往往可以引入一个中间层来解决问题:分离两个模型之间的变化,这样只要修改中间层即可,虽然这样会增加系统的复可以杂度,但是可以带给你很大的灵活度 无需在一开始的时候就插入间接层,在需要修改的时候,进行修改就好 某些面向对象的数据库,可以提供不同版本的自动迁移功能,减少数据迁移时的工作量。需要注意数据结构的变化,以及修改数据的访问方法 修改接口 如果所有的接口影响的信息都在你的掌握之下,那么修改不成问题 问题在于对于那些已经发布了的接口,你需要考虑存修改接口所带来的问题 所以,一般上我们新的接口都需要兼容旧的接口。直到所有的用户把迁移到新的接口里 另一种是,不要过早发布你的接口。或者可以在旧的接口中产生一个警告,然红会尽快地迁移到新的接口 难以通过重构手法完成的设计改动 在某些情况下,我们可以有效地进行重构,对于安全性的问题,常常遇到 所以,我们常常在重构之前,进行预想重构的方法,如果重构足够简单,那么没有问题,可以直接重构 何时不该重构 代码过于混乱,重构的难度比直接重写要高 重构之前,代码必须要能够正常运作 一个折中的办法:将“大块头软件”重构为封装良好的小型组件。然后就可以逐一对组件进行重构或重建 项目时间接近最后期限,你应该避免重构 2.6 重构与设计 重构肩负着一项特殊的使命:它和设计互补 初识编程的时候,埋头写代码,混混噩噩地进行开发。发现,事先做好设计可以节省返工的高昂成本 也有另一种观点,重构可以取代设计,不断的重构可以获得良好的设计软件 我的看法:无论是先设计后开发,还是后期进行重构。都表明开发人员要有一定的软件设计能力,因为我们无法避免地会发现程序中的问题(BUG)。随着编程的经验的提高,和对开发的理解不断提高自己的设计能力。不如把两种方法结合起来。在开发中重构,在重构中设计。开发前期,有章法可寻;后期通过不断重构完善设计。在设计和重构之间相辅相成。 重构可以带来更简单的设计,同时又不损失灵活性,也降低了设计过程中的难度,减轻了设计压力。 劳而不获 在软件开发的过程中,常常会遇到一些性能问题。(学员信息管理系统、帐号管理) 哪怕你完全了解系统,也请实际度量他的性能问题,不要臆测。臆测会让你学到一些东西,但十有八九是错的 2.7 重构与性能 并不赞同提高设计的纯洁性二忽略性能,把性能依赖于硬件上 三种快速软件的编写方法: 时间预算法:适用于实时系统 持续关注法:要求程序员在任何时间上做任何事情,都要设法保持系统的高性能。 利用90%以上的统计数据:在开发前期不用特别关注性能问题,后期在集中优化(用性能度量工具,注意要把握好测试的幅度,不可过大) 重构可以帮助我写出更好更快的软件,在短期看来的确可能使软件变慢,但在优化阶段的软件性能调整上更容易,最终还会的到更好的效果 2.8 重构起源何处 来源与程序员对代码的理解,起到推动作用的是Ward Cunningham & kent Beck下使用Smalltalk","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"重构","slug":"重构","permalink":"https://ilifexiao.github.io/tags/重构/"}]},{"title":"重构,第一个案列","slug":"重构改善既有代码的设计/重构,第一个案列","date":"2018-04-27T09:19:34.000Z","updated":"2018-07-11T06:05:14.000Z","comments":true,"path":"2018/04/27/重构改善既有代码的设计/重构,第一个案列/","link":"","permalink":"https://ilifexiao.github.io/2018/04/27/重构改善既有代码的设计/重构,第一个案列/","excerpt":"","text":"第一章、重构,第一个案列1.1 起点例子影片出租软件 Moive Rental Customer priceCode:int daysRented:int statement() 问题函数:123456789101112131415161718192021222324252627282930313233343536373839404142434445public string statement () { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result= \"Rental Record for \"+ getName () +\"\\n\"; while (rentals.hasMoreElements()) { double thisAmount = 0; Rental each = (Rental) rentals.nextElement (); // determine amounts for each line switch (each.getMovie().getPriceCode ()) { case Movie.REGULAR: thisAmount += 2; if (each.getDaysRented() > 2) thisAmount += (each.getDaysRented ()-2) * 1.5; break; case Movie. NEW_RELEASE: thisAmount += each.getDaysRented() * 3; break; case Movie.CHILDRENS: thisAmount += 1.5: if (each.getDaysRented() > 3) thisAmount + (each.getDaysRented() -3) * 1.5; break; } // add frequent renter points frequentRenterPoints ++; // add bonus for a two day new release rental if ( (each.getMovie () .get PriceCode () == Movie. NEW_RELEASE) && each. getDaysRented() > 1) frequentRenterPoints ++; // show figures for this rental result +=\"\\t\" + each.getMovie().getTitle()+ \"\\t\"+ string.valueof (thisAmount) + \"\\n\"; totalAmount += thisAmount; } // add footer lines result += \"Amount owed is \"+ String.valueof (totalAmount) + \"\\n\"; result += \"You earned\"+ String.valueof (frequentRenterPoints) + \" frequent renter points\"; return result;} 问题: 其中statement()负责输出用户租借影片的信息,但是其包含的内容过多,做了许多其他类应该做的事情 后期需要修改程序的时候(增加了影片类别、计费模式、新的输出样式等),将会导致大量的重复代码和维护问题 解决: 发现要添加一个新的功能,在原有的代码结构上难以完成,就应该先重构该代码,使其添加容易进行 1.2 重构的第一步 为即将修改的代码建立一组可靠的测试环境,避免引入其他BUG 好的测试是重构的根本 测试必须有自我检验功能 理由: 减少重构过程中的对比问题 1.3 分解并重组statement()问题: 首先statement()函数过长。代码块越小,代码的功能就愈容易管理,代码的处理和移动速度也就月轻松 降低代码的重复量 解决: 将逻辑泥团,提炼函数(Extract Method)。比如switch语句 每次修改都应该检测一次,避免意外地引入BUG(返回值错误、数据丢失等) 提炼函数后,建议修改变量的名称。因为好的代码应该清晰地表达出自己的功能,变量名称是代码清晰的关键(阅读代码的对象是人类) 现在大部分的IDE都提供了不同程度的重构功能 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152public string statement () { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result= \"Rental Record for \"+ getName () +\"\\n\"; while (rentals.hasMoreElements()) { double thisAmount = 0; Rental each = (Rental) rentals.nextElement (); // determine amounts for each line thisAmount = amountFor(each) // add frequent renter points frequentRenterPoints ++; // add bonus for a two day new release rental if ( (each.getMovie () .get PriceCode () == Movie. NEW_RELEASE) && each. getDaysRented() > 1) frequentRenterPoints ++; // show figures for this rental result +=\"\\t\" + each.getMovie().getTitle()+ \"\\t\"+ string.valueof (thisAmount) + \"\\n\"; totalAmount += thisAmount; } // add footer lines result += \"Amount owed is \"+ String.valueof (totalAmount) + \"\\n\"; result += \"You earned\"+ String.valueof (frequentRenterPoints) + \" frequent renter points\"; return result;}private double amountFor(Rental aRetal) { double result = 0; switch (aRetal.getMovie().getPriceCode ()) { case Movie.REGULAR: result += 2; if (aRetal.getDaysRented() > 2) result += (aRetal.getDaysRented ()-2) * 1.5; break; case Movie.NEW_RELEASE: result += aRetal.getDaysRented() * 3; break; case Movie.CHILDRENS: result += 1.5: if (aRetal.getDaysRented() > 3) result + (aRetal.getDaysRented() -3) * 1.5; break; } return result;} 1.3.1 搬移“金额计算”代码问题: amountFor(),这个函数只使用了来自Rental类的信息,却没有使用Customer类的信息 在大多数情况下,函数应该放在它所使用的数据的所属对象内 解决: 将amountFor(),这个函数移动到Rental类中 使用搬移函数(Move Method) Retal类 修改函数信息(参数、变量名称、函数名称等) 1234567891011121314151617181920class Retal...double getChange() { double result = 0; switch (getMovie().getPriceCode ()) { case Movie.REGULAR: result += 2; if (each.getDaysRented() > 2) result += (getDaysRented ()-2) * 1.5; break; case Movie. NEW_RELEASE: result += getDaysRented() * 3; break; case Movie.CHILDRENS: result += 1.5: if (getDaysRented() > 3) result + (getDaysRented() -3) * 1.5; break; } return result;} 尝试调用函数,检测代码是否正常工作 1234class Customer...private double amountFor(Rental aRental) { return aRental.getChage();} 删除amountFor()函数 12345678910111213141516171819202122232425262728293031public string statement () { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result= \"Rental Record for \"+ getName () +\"\\n\"; while (rentals.hasMoreElements()) { double thisAmount = 0; Rental each = (Rental) rentals.nextElement (); // determine amounts for each line thisAmount = each.getChange() // add frequent renter points frequentRenterPoints ++; // add bonus for a two day new release rental if ( (each.getMovie () .get PriceCode () == Movie. NEW_RELEASE) && each. getDaysRented() > 1) frequentRenterPoints ++; // show figures for this rental result +=\"\\t\" + each.getMovie().getTitle()+ \"\\t\"+ string.valueof (thisAmount) + \"\\n\"; totalAmount += thisAmount; } // add footer lines result += \"Amount owed is \"+ String.valueof (totalAmount) + \"\\n\"; result += \"You earned\"+ String.valueof (frequentRenterPoints) + \" frequent renter points\"; return result;} 删除一些多余变量thisAmount 尽量删除一些临时变量,避免大量参数互相传递,导致性能等问题发生 123456789101112131415161718192021222324252627public string statement () { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result= \"Rental Record for \"+ getName () +\"\\n\"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement (); // add frequent renter points frequentRenterPoints ++; // add bonus for a two day new release rental if ( (each.getMovie () .get PriceCode () == Movie. NEW_RELEASE) && each. getDaysRented() > 1) frequentRenterPoints ++; // show figures for this rental result +=\"\\t\" + each.getMovie().getTitle()+ \"\\t\"+ string.valueof (each.getChange()) + \"\\n\"; totalAmount += each.getChange(); } // add footer lines result += \"Amount owed is \"+ String.valueof (totalAmount) + \"\\n\"; result += \"You earned\"+ String.valueof (frequentRenterPoints) + \" frequent renter points\"; return result;} 1.3.2 提炼“常客积分计算”代码问题: 积分的计算根据影片的类型二不同,但是不像收费规则那样变化那么多 解决: 提炼函数(Extract Method) 搬移函数(Move Method) 1234567891011121314151617181920212223242526272829303132public string statement () { double totalAmount = 0; int frequentRenterPoints = 0; Enumeration rentals = _rentals.elements(); String result= \"Rental Record for \"+ getName () +\"\\n\"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement (); frequentRenterPoints += each.getFrequentRenterPoints() // show figures for this rental result +=\"\\t\" + each.getMovie().getTitle()+ \"\\t\"+ string.valueof (each.getChange()) + \"\\n\"; totalAmount += each.getChange(); } // add footer lines result += \"Amount owed is \"+ String.valueof (totalAmount) + \"\\n\"; result += \"You earned\"+ String.valueof (frequentRenterPoints) + \" frequent renter points\"; return result;}class Rental... int getFrequentRenterPoints() { // add bonus for a two day new release rental if ((each.getMovie().getPriceCode() == Movie.NEW_RELEASE) && each.getDaysRented() > 1) { return 2; } else { return 1 }} 1.3.3 去除临时变量问题: 临时变了可能是一个问题,会导致使得函数复杂 解决: 运用以查询代替临时变量(Replace Temp with Query) 并利用查询函数(Query Method) 1234567891011121314151617181920212223242526272829303132333435public string statement () { Enumeration rentals = _rentals.elements(); String result= \"Rental Record for \"+ getName () +\"\\n\"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); // show figures for this rental result +=\"\\t\" + each.getMovie().getTitle()+ \"\\t\"+ string.valueof (each.getChange()) + \"\\n\"; } // add footer lines result += \"Amount owed is \"+ String.valueof (getTotalChange()) + \"\\n\"; result += \"You earned\"+ String.valueof (getTotalFrequentRenterPoints()) + \" frequent renter points\"; return result;}private double getTotalChange() { double result = 0; Enumeration rentals = _rentals.elements(); while(rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += each.getChange(); } return result;}private int getTotalFrequentRenterPoints() { int result = 0; Enumeration rentals = _rentals.elements(); while(rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); result += each.getFrequentRenterPoints() } return result;} 处理思考: 大多数重构都会减少代码量,但是这次却增加了代码量 还有原本只需要一次的循环,现在却需要三次,降低了性能 但是,现在还无需担心重构带来的性能问题,后续会慢慢解决的 编写htmlStatement() 这里复用了原来的statement()函数的所有功能 后期,可以使用构造模板函数(Form template Method) 123456789101112131415public string htmlStatement () { Enumeration rentals = _rentals.elements(); String result= \"<h1>Rental for<em> \"+ getName () +\"</em></h1><p>\\n\"; while (rentals.hasMoreElements()) { Rental each = (Rental) rentals.nextElement(); // show figures for this rental result += each.getMovie().getTitle()+ \":\"+ string.valueof (each.getChange()) + \"</br>\\n\"; } // add footer lines result += \"<p>You owed <em>\"+ String.valueof (getTotalChange()) + \"</em><p>\\n\"; result += \"On this rental you earned <em>\"+ String.valueof (getTotalFrequentRenterPoints()) + \"</em> frequent renter points<p>\"; return result;} 这里客户可能需要修改影片的分类规则,然后与之相对应的费用、积分计算等都需要重新重构 常常做的是,把因条件而异的代码替换掉 1.3.4 运用多态取代与价格相关的条件逻辑问题: 不要在另一个对象的属性基础上运用switch语句 如果不得已使用,也应该放在自己的数据上使用,而不是别人的数据上使用 这里暗示getChange()应该移动到Moive中 添加了参数:dayRented用于表示租借的天数 这里选择将dayRented作为参数传递,而不用Moive,原因在于Moive是变化的复杂类型,这种变化不稳定,需要尽量控制它的影响 将影片类型变化的东西全部放在影片里面 123456789101112131415161718192021222324252627282930313233343536373839class Moive...double getChange(int dayRented) { double result = 0; switch (getPriceCode ()) { case Movie.REGULAR: result += 2; if (dayRented > 2) result += (dayRented -2) * 1.5; break; case Movie. NEW_RELEASE: result += dayRented * 3; break; case Movie.CHILDRENS: result += 1.5: if (dayRented > 3) result + (dayRented -3) * 1.5; break; } return result;}int getFrequentRenterPoints(int dayRented) { if ((getPriceCode() == Movie.NEW_RELEASE) && dayRented > 1) { return 2; } else { return 1 }}class Rental... doubel getChange() { return _moive.getChagre(_dayRented)}int getFrequentRenterPoints() { return _moive.getFrequentRenterPoints(_dayRented)} 1.3.5 终于……我们来到了继承问题: 影片有不同类型,根据不同类型做着不同的工作,但也有相似之处 这里暗示我们可以建立Moive的子类,拥有不同的计费方法 但是,一部影片可以在生命周期内修改自己的分类,一个对象却不能在生命周期里修改自己所属的类 这里可以引入中间层来完成,state模式 这样,就可以在Price对象内进行子类化的动作,于是便可在任何必要的时候修改价格(更换对象的类型) 联想到了iOS中的类簇UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; 解决: 以State/Strategy取代类型码(Replace Type Code with State/Strategy) 搬移方法(Move Method) 以多态取代条件表达式(Replace Condition with Polymorphism ) 首先使用自封装字段(Self Encapsulate Filed) 使用设值函数来代替 123456class Moive public Moive(String title, int priceCode) { _title = title; // 影片类型 setPriceCode(priceCode) } 然后编译测试,确保没有破坏任何东西 新建抽象Price类,设置抽象方法getPriceCode() 123456789101112131415161718192021abstract class Price { abstract int getPriceCode();}class ChildrenPrice extends Price { int getPriceCode() { return Moive.CHILDRENS }}class NewReleasePrice extends Price { int getPriceCode() { return Moive.NEW_RELEASE }}class RegularPrice extends Price { int getPriceCode() { return Moive.REGULAR }} 修改Moive类内的”价格代号”访问函数 子类可以赋值给父类 1234567891011121314151617181920212223class Moive... public int getPriceCode() { return _price.getPriceCode; } public void setPriceCode(int arg) { switch (arg) { case REFULAR: _price = new RegularPrice(); break; case CHILDRENS: _price = new ChildrenPrice(); break; case NEW_RELEASE: _price = new NewReleasePrice(); break; default: throw new IllegalArgumentExecption(\"Incorrent Price Code\"); } } // 这里面就包含电影的类型 private Price _price; 对getCharge()实施Move Method 123456789101112131415161718192021222324252627class Price...double getChange(int dayRented) { double result = 0; switch (getPriceCode ()) { case Movie.REGULAR: result += 2; if (dayRented > 2) result += (dayRented -2) * 1.5; break; case Movie. NEW_RELEASE: result += dayRented * 3; break; case Movie.CHILDRENS: result += 1.5: if (dayRented > 3) result + (dayRented -3) * 1.5; break; } return result;}class Moive...double getChange(int dayRented) { return _price.getChange(dayRented)} 以多态取代条件表达式(Replace Condition with Polymorphism ) 1234567891011121314151617181920212223242526272829303132333435363738class Price... abstract double getChange(int dayRented);class ChildrenPrice extends Price { int getPriceCode() { return Moive.CHILDRENS; } double getChange(int dayRented) { double result = 1.5: if (dayRented > 3) result + (dayRented -3) * 1.5; return result; }}class NewReleasePrice extends Price { int getPriceCode() { return Moive.NEW_RELEASE; } double getChange(int dayRented) { return dayRented * 3; }}class RegularPrice extends Price { int getPriceCode() { return Moive.REGULAR; } double getChange(int dayRented) { double result += 2; if (dayRented > 2) result += (dayRented -2) * 1.5; return result; }} 同样处理getFrequentRenterPoints(int dayRented) 这里不打算设置getFrequentRenterPoints(int dayRented)为抽象方法,设置为默认行为 然后在特定的子类中覆盖该方法 1234567891011121314class Moive...int getFrequentRenterPoints(int dayRented) { return _price.getFrequentRenterPoints(dayRented);}class Price...int getFrequentRenterPoints(int dayRented) { return 1;}class NewReleasePriceint getFrequentRenterPoints(int dayRented) { return (dayrented > 1) ? 2 :1 ;}","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"重构","slug":"重构","permalink":"https://ilifexiao.github.io/tags/重构/"}]},{"title":"不跟随被踩烂了的成功之路","slug":"互联网+/不跟随被踩烂了的成功之路_杨致远","date":"2018-04-26T03:09:30.000Z","updated":"2018-07-11T06:05:51.000Z","comments":true,"path":"2018/04/26/互联网+/不跟随被踩烂了的成功之路_杨致远/","link":"","permalink":"https://ilifexiao.github.io/2018/04/26/互联网+/不跟随被踩烂了的成功之路_杨致远/","excerpt":"","text":"创新引领时代潮流创新,做自己喜欢做的事情。才有继续做下去的能力 机会是留给有准备的人的 即使失败,也有重新来过的勇气 创新能走出新的成功之路不服输的性格决定了他的命运 拥有一颗热爱冒险的心,创新的头脑和勇敢的精神 不创新,必死无疑互联网是一个以技术为依托的行业,谁的产品和服务更能满足大众的需求,谁就能占据市场制高点 不断寻求的创新云计算 传感器 大数据 想创新必须感犯错误企业想要维持长久的创新力,就必须要改变企业的文化,要敢于激进冒险犯错误 雅虎的没落,谷歌的崛起","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"独特的视角和预见性","slug":"互联网+/独特的视角和预见性_马云","date":"2018-04-23T08:52:26.000Z","updated":"2018-07-11T06:07:26.000Z","comments":true,"path":"2018/04/23/互联网+/独特的视角和预见性_马云/","link":"","permalink":"https://ilifexiao.github.io/2018/04/23/互联网+/独特的视角和预见性_马云/","excerpt":"","text":"马云:独特的视角和预见性执行力与创新力并存创业不能停留在理念和幻想上,idea可以有无数个,action只能有一个 有时去执行一个错误的决定,总比优柔寡断或者没有决定要好得多,因为在执行过程中你可以有更多的时间和机会区发现并改正错误 一个思想上的巨人,行动上的矮子注定智能活在会议室里,一旦进入激烈的显示市场中就回成为弱者 似我者俗,学我者死并不是所有的成功精髓都能够学会 一种独特的价值观,商业模式可以学习,互联网技术可以模仿,公司特对可以随意组件,可是理念,价值观这种无形的东西却无从学起 成功的方法千千万万,失败的情况却惊人地相似 不要保守,去干高风险的事风险和机会是紧连在一起的 不要等到所有一切都准备好了才开始 创新就是要与明天竞争马云在清华“创新论坛”演讲时,曾和众人分享了自己对企业创新的看法,“创新就是创造新的价值,创新不是因为你要打败对手,不是为更大的名,而是为了社会,为了客户,为了明天,创新不是为对手竞争,而是跟明天竞争。” 深刻理解创新的内涵:使命感 企业内部要有创新机制独立思考,独立判断 乐观积极的态度 讲信用 自由者,坚持做自己 创新要把控好节奏","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"模仿也是一种创新","slug":"互联网+/模仿也是一种创新_马化腾","date":"2018-04-22T12:26:43.000Z","updated":"2018-07-11T06:08:01.000Z","comments":true,"path":"2018/04/22/互联网+/模仿也是一种创新_马化腾/","link":"","permalink":"https://ilifexiao.github.io/2018/04/22/互联网+/模仿也是一种创新_马化腾/","excerpt":"","text":"马化腾:模仿也是一种创新青出于蓝而胜于蓝 模仿而是一种创新力,关键在于怎样模仿,怎样在模仿的基础上进行创新 任何行业的发展都是建立在前人的基础之上的,重复的发明,是极大的浪费 模仿有两个基本的要诀:一是选择模仿的对象,二是把我模仿的时机 单纯的模仿永远都不可能超越前者,要学会在别人的基础上进行创新,本土化的融合 创新就是要做出同类产品没有的有点互联网的同类竞品较多 竞争需要优势,做到人无我有,人有我优 模仿,最稳妥的创新创新是一件充满风险的事情,需要做好对风险有效的管理和控制 提前做好新项目的调研、计划等准备工作 创新就是整合,创新就是运作一站式多方位服务粉肠方便,这也是腾讯能够迅速做大的根本原因 创新的三个层次:技术创新、产品创新和应用创新 适合国情,就是最有创意的ICQ的本土化,需要把我时机,错过了时机,即使你和对手不相上下,用户也难以迁移 “QQ”是“拿来”的创新QQ模仿ICO,同期也有许多的同质软件,它在很多地方进行一系列的创新,这才是腾讯腾讯打败众多模仿者的根本原因 以QQ为大本营,建立一个全方位服务的大型互联网社区 创新和引入不矛盾互联网的顶级技术在美国,但未来的市场在中国","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"创新的常规是打破常规","slug":"互联网+/创新很重要,有价值的创新更重要_李开复","date":"2018-04-19T11:54:35.000Z","updated":"2018-07-11T06:16:28.000Z","comments":true,"path":"2018/04/19/互联网+/创新很重要,有价值的创新更重要_李开复/","link":"","permalink":"https://ilifexiao.github.io/2018/04/19/互联网+/创新很重要,有价值的创新更重要_李开复/","excerpt":"","text":"创新的常规是打破常规创新的最大障碍就是思维定势,固定的思维会限制我们的思考方式,从而按照固定的轨道运行 互联网经济将就的是规模效益 一定要洞悉未来,敢于打破常规 规矩、规则、经验能使我们的工作更科学高效 不盲从就是一种创新在商业领域,盲从不仅没有多大的积极作用,反倒是一种埋没自身的危险举动 不要少了boos就无法工作,信任,放权管理能够减少沟通成本 一流的人才是很重要的,要有自己的价值观、世界观 打造自己的创新工厂创新推动科技,技术改变生活 不要忘记自己的初衷 不断地创新自己,颠覆自己,才可能创造出改变世界的奇迹 以人为本是企业保持持久创新力的关键管理他人就是希望你自己如何被管 在人才管理方面,不仅需要能够挑出优秀的人,还要善于发现每个人的所长,将他们的潜力挖掘出来,使其独当一面 用心的创新更重要要留神不要走入新颖但缺乏实用价值的歧途 创新的三个关键点:新颖,有用,可行 要在不同的角度去思考问题,用户,市场等 创新是为了成为更有价值的公司ebay vs 淘宝:商业模式的创新MSN vs QQ:细节的创新 要做一流的公司,首先要站在全球的行业高度和视角上,借助创新做更有价值的事,只有这样才能提高自己的竞争力 创新并不是一蹴而就的事情,它需要细致的观察力、灵感火花的闪现、长期的技术积累、漫长的技术开发 孵化基地_创新工厂 树立新的价值理念伟大的发明往往是从奇思妙想开始的 迭代式创新 创新受阻的核心因素在于思想理念上的守规矩 循序渐进才是比较明智的改革","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"感想他人之不敢想","slug":"互联网+/感想他人之不敢想_李彦宏","date":"2018-04-19T11:54:18.000Z","updated":"2018-07-11T06:07:52.000Z","comments":true,"path":"2018/04/19/互联网+/感想他人之不敢想_李彦宏/","link":"","permalink":"https://ilifexiao.github.io/2018/04/19/互联网+/感想他人之不敢想_李彦宏/","excerpt":"","text":"感想他人之不敢想企业越发展,转型越困难 坚定的信念是目标实现的有力支持 要有专注精神形成T字形人才,在一个领域扎根下去,在许多潮流中,容易迷失自己的方向和价值,只许拿出部分10%的资源来创新、学习 做自己喜欢的事,若是只为其他目的去涉猎自己不喜欢的方向,也难以成功,和比真正喜欢他的人做得更好 要扎下去,并且要扎得深你的深度,决定你的高度、影响力 技术和市场的结合 创新是百度的灵魂在事关百度原则上的地方,李彦宏从来没有妥协 企业管理的风格,简单,不用打卡 用自己的优点去求变,去创新降低创新的风险,弯道超车 在自己熟悉的领域借助自己的优势创新才更有效率,否则连许多基本的常识都需要学习,则难以成功 要比别人看得更深刻看到别人没有看到的发展机遇,发现别人没有发现的价值 要善于发现,善于思考,能够预测行业的发展 创新的目的是满足用户的需求","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"创新就是要颠覆市场游戏规则","slug":"互联网+/创新就是要颠覆市场游戏规则_周鸿祎","date":"2018-04-15T03:58:08.000Z","updated":"2018-07-11T06:06:29.000Z","comments":true,"path":"2018/04/15/互联网+/创新就是要颠覆市场游戏规则_周鸿祎/","link":"","permalink":"https://ilifexiao.github.io/2018/04/15/互联网+/创新就是要颠覆市场游戏规则_周鸿祎/","excerpt":"","text":"周鸿祎:创新就是要颠覆市场游戏规则要创新,就要进行颠覆式创新360推出免费杀毒,有了用户就会有市场 颠覆式创新要从微创新开始创新不能一味地求大求快,要做有价值的创新 微创新的好处,风险小,可以随时调整目标,更容易到达目的地 争议力就是创新力3Q大战、建议卸载、雷电事件 创新管理方式,草根创业孵化360随身WIFI…..(买了一个用了几次就坏了。。。) 公司内部拥有孵化团队,没有等级限制 公司不能有绝对的管理者,否则九容易出现划分地盘的问题 将公司划分为一个个小团度,类似于分布式系统 创新真正的“道”是价值观微软废弃员工排名等级制度(由上司来决定) 创新就是要与众不同“所有的创新,只要复合与众不同的精神,加上屡败屡战的韧性,再加上接地气的非常务实的操作方法,到市场中,到用户中去,你采用可能创业成功” “绝大多数的创新的想法一定失败,最后都是屡败屡战” 如果你决定了要创新,九必须有坚定不移的信心 要免费!就是根你们不一样","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"创新就是做别人没有做成功的事","slug":"互联网+/创新就是做别人没有做成功的事_雷军","date":"2018-04-12T05:15:33.000Z","updated":"2018-07-11T06:07:17.000Z","comments":true,"path":"2018/04/12/互联网+/创新就是做别人没有做成功的事_雷军/","link":"","permalink":"https://ilifexiao.github.io/2018/04/12/互联网+/创新就是做别人没有做成功的事_雷军/","excerpt":"","text":"雷军:创新就是做别人没有做成功的事创新是为了更好地迎合人心现在人讲究精致、时尚、良好的视觉效果。只有漂亮的东西才能够得到传播 小米的系统更新快,通过不断迭代,解决问题 也就是说创新要满足市场的需求 前所未有的粉丝效应想好用户的定位,打着“为发烧而生”的口号,形成品牌效应 打造小米社区,来获取用户的资料,体验,通过不断的交流来完善自己的设计 推出卡通形象,刻画企业文化宣传 粉丝网,通过粉丝强大的效应 互联网时代,消费者也是生产者,只有消费者真正地参与进来,甚至参与到生产过程中,这个产品才会做的更有价值 打造独特的商业模式通过低价高配来完成商业的起点,只要树立了良好的口碑,背后就有更大的市场可以挖掘 企业要有技术壁垒,不能让其他竞争着轻易地超过 高新技术企业要想在行业内崭露头角,光有技术上的创新还是不够的,还要有大格局,全局眼光,懂得从 商业模式上进行创新布局 接着做别人没有做好的事雷军曾说:“在创新上,大家的理解是有偏差的。很多人认为只有巨大的颠覆才叫创新,可是,我们不能因此而忽略那些微小的创新所带来的变革” 创新是一件需要很大勇气的事情,要想成功,就要在不断的实践中继续改良创新 颠覆世界的创新很重要,但继续在别人的创新失败的基础上在创新也不失为一种捷径 挖聪明人共事只有优秀的团队才能做出优秀的产品 雷军曾说:“一年例是用80%的实践来寻找对的人” 员工的价值观和企业的价值观是相符是非常重要的 在留住人才上,涨薪水、股权、地位 没有考核和打卡,不需要一套晋升制度,容易导致单纯的为了绩效和考核二努力,这在一定程度上是对创新的扭曲 不让团队过大,无需讨好老板,只要专心的做自己的事情就可以了 一个企业的成功,往往离不开一个优秀的团队 目的、是为了培养员工的责任感和使命感,让员工树立正确的价值观 打造属于小米的营销板斧转发微博送手机,在小米营销中最屡试不爽的招式 粉丝群体,有求必应 赋予客服一定的权利 一个企业想要成功,树立良好的品牌效应很重要 创新就是让用户尖叫要想达到这个咪表,就要向办法让用户用的舒服,二不是高管在上地向用户炫耀","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"思想上的创造才有价值","slug":"互联网+/思想上的创造采用价值_任正非","date":"2018-04-10T13:42:57.000Z","updated":"2018-07-11T06:08:13.000Z","comments":true,"path":"2018/04/10/互联网+/思想上的创造采用价值_任正非/","link":"","permalink":"https://ilifexiao.github.io/2018/04/10/互联网+/思想上的创造采用价值_任正非/","excerpt":"","text":"任正非:思想上的创造才有价值做出属于自己的特色与市场结合起来的技术创新才是有价值的 要创新出能卖掉的东西,就得反幼稚技术脱离市场的结果比较严重:维修成本高于生产成本、没和合适的配件、导致很多产品变成一文不值 技术上盲目创新和过度创新都是不可取的,技术并非月先进越好,其先进性必须一市场为导向,以消费为目标,否则会导致产品过剩 在技术创新上提倡:技术市场化、市场技术化 在企业实际经营中,最好的技术、最好的研发固然是其核心竞争力的表现,但必须要有市场基础 创新要以市场为依托,技术和设备要为生产现状服务,脚踏实地才是企业创新最稳妥的选择 具备忧患意识才能不断创新成就和落魄都会影响现在你看待未来的视线,不要容易被影响 创新要站在巨人的肩膀上在华为,产品绝大部分都不是原创发明的,而是组合型创新。 技术很重要,但是合作更重要 站在巨人的肩膀上,借鉴前人的经验来高创新,才能实时求是地、高效地做产品,创新才更具有改变企业的价值 高工资推动创新人才是一个企业发展的源泉与动力。 脱掉“草鞋”换上“美国鞋”企业发展到一定程度,需要进行改革创新,更新原来的管理模式,引进新的管理模式,从而形成新的管理模式。形成一个良性循环","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"知识相互匹配催生创新力","slug":"互联网+/知识相互匹配催生创新力_雷德-霍夫曼","date":"2018-04-09T12:09:53.000Z","updated":"2018-07-11T06:08:33.000Z","comments":true,"path":"2018/04/09/互联网+/知识相互匹配催生创新力_雷德-霍夫曼/","link":"","permalink":"https://ilifexiao.github.io/2018/04/09/互联网+/知识相互匹配催生创新力_雷德-霍夫曼/","excerpt":"","text":"雷德-霍夫曼:知识相互匹配催生创新力坚持差异化就是创新他给LinkedIn的定位不仅仅是一家招聘网站,而是涵盖招聘功能的职业社交网站 通过职业身份,帮助用户简历档案,出了可以像普通招聘网站那样就职外,还能实现职场交友、职场人脉的搭建 可以和同行、HR、行业精英等,可以与业内人士一起探讨工作技巧、行业发展趋势、职业发展前景等(大学说:可以和企业人士交流,企业也可以发掘有潜力的学生) 创新就是竞争,就是不断迭代加快自己的研发速度,将产品放入市场检验,在不断地迭代 硅谷之所以能够保持创新力,很大的程度是因为竞争 创新还要与企业的发展步伐一致 本土创新,成功在华扎根在中国合资企业共同管理,聘请本地有经验的人来管理公司,减少管理汇报的难度,和用户多的公司合作 不砸钱,照样拥有海量用户LinkedIn用户快速增长的秘密武器:LinkedIn是世界上最早使用数据技术驱动增长的公司 数据分析的范围:销售、市场营销、产品、风控、客户服务、工程、各运营部门 数据是一个非常就有参考价值的决策参考项(微信小程序的数据分析) 主要借助猎头服务以及向企业客户售卖人才简历来变现 创新要放低姿态、覆盖更多人群通过创新的好友关系维度功能 发现栏目:发现事,发现人,对应线下活动消息 双品牌运营,创新与挑战同在规模越大的公司,月重视对区域市场的控制权,为了避免造成公司资源分散,或区域高管另起炉灶侵吞公司资产,很多跨过公司不会采取”双品牌”的运营方法。 LinkedIn的核心理念是,“连接全球” 在国内的”赤兔”APP的运营,是LinkedIn在管理上极具创造力的表现,正是这种“一国两制“的求同存异的发展理念,让LinkedIn打破了跨国公司在华失败的魔咒","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"创新就是要敢于冒险","slug":"互联网+/创新就是要敢于冒险_布莱恩-切斯基","date":"2018-04-07T08:07:35.000Z","updated":"2018-07-11T06:06:39.000Z","comments":true,"path":"2018/04/07/互联网+/创新就是要敢于冒险_布莱恩-切斯基/","link":"","permalink":"https://ilifexiao.github.io/2018/04/07/互联网+/创新就是要敢于冒险_布莱恩-切斯基/","excerpt":"","text":"第三章、布莱恩-切斯基:创新就是要敢于冒险创新就是人们提出异议时会想起你只要有人需要短租,只要有无数的房主愿意用自己的房子提供短租,那么在巨大的市场面前。任何异议抗议都是惨白无力的 任何一个创新举动都会遇到各种各样的异议,对于互联网公司来说,如果日复一日地进行重复,所有举措都没有任何意义,那么距离破产也不远了 任何一个行业都有它的既定规则,要学会打破规则,建立新的规则 分享闲置也是一种创新2015年Airbnb的估值达到255亿美元,其中一个重要的原因是它颠覆了酒店行业 在Airbnb的服务费中,获取高溢价的最佳方式就是创造出美的差异化 通过为每一处名居注入人文价值来实现高定价 Airbnb仅仅是对等经济的一个例子,共享经济还在潜移默化地影响着我们每个人的生活。改变着大众的生活方式 在管理上要保持好奇心Airbnb的创始人并没有任何管理经验,他关注的两个方面:一、会造成公司失败的因素;二、专注与自己两三个比较有激情的领域,之所以关注,是因为自己能够给他们提供独一无二的价值 他的两个学习方式:一是试错,二是找人。只要找对人,你就能快进了(听君一席话,胜读十年书) 他通过拜访许多知名人士,以及阅读各种书籍来提高自己的管理水平 承认弱点,才能更有创造力一个人只有敢于承认弱点,才能坦诚地面对自己的劣势和不足,才能不断改进和完善自己,赢得更多人的支持 苹果的熟悉设计师乔尼-伊夫:“坚守纪律、拒绝诱惑对于产品的研发和创新的重要性” 一定要有冒险精神布莱恩-切斯基:“如果你有创业的冲动,现在就应该放手一搏,切勿等待,因为无情的岁月会扼杀一个人的冒险精神” 人类本身心中就有对自己渴望做的事情,无论你现在的方向在哪,他总会指引你前往 越是“不可理喻“越接近成功事实证明,“不可理喻”也是一种创新力,被人否定没什么,关键在于要怎样让“不可理喻”的点子变成现实 拥有强大的心里尤为重要","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"创新就是要有形而无序","slug":"互联网+/创新就是要有形而无序_扎克伯格","date":"2018-04-07T00:05:23.000Z","updated":"2018-07-11T06:07:00.000Z","comments":true,"path":"2018/04/07/互联网+/创新就是要有形而无序_扎克伯格/","link":"","permalink":"https://ilifexiao.github.io/2018/04/07/互联网+/创新就是要有形而无序_扎克伯格/","excerpt":"","text":"第二章、扎克伯格:创新就是要有形而无序一、创新必须具备扎实的技术扎克伯格的成功,很大程度上是因为他扎实的编程技术,并能够在此基础上进行有效的创新 基础是前提,创新是关键 一个人的基本技能和其对问题的解决能力是十分重要的 二、有趣的创新很重要并不是任何一项创新都是有价值的,要想让广大用户更乐于接受创新,就必须要想办法让你的创新变得更有趣一些 保持纯真的原味性有时比过度商业化更有意义 随着社会的不断发展,人们越来越关心趣味性与实用性 三、创新必须要坚持自己的判断有人的地方就有市场 重要的是对自己的想法的坚持 四、创新要有坚定的信念在他脑海里有一个关于互联网的美好梦想,他要做的便是吧这些梦想一个个地转为现实 五、创新并不重要,有需求的创新才重要创新的根本目的是为了满足用户的需求,有需求才会用人去使用,有更多的人使用才能创造出更多的价值 关注用户的产品体验,积极的改良创新 值得注意的是,用户们的需求并不是一成不变的,随着社会的发展,人们的生活的变化,用户的需求也会从初级变得高级 首先就必须结整个社会环境,人们的生活习惯等多方面区准确的了解他们的内心需求,只有建立在用户需求基础上的创新才是用商业价值的,才是值得我们为之去努力、奋斗的目标 六、创新也要在营销上耍耍新花样在信息爆炸的时代,酒香也怕巷子深,即使技术很棒,不去宣传的话,也可能会无人问津 更好地让用户体验和商业利润有机地结合在一起。看不到广告却出处隐藏着广告 形成品牌效应,在一定程度上形成一种良性循环 七、把与众不同练就成一种本能在激烈的市场竞争中,开拓出一条新路很重要。要么拥有引入注目的产品销售方式,要没人产品本身非常吸引眼球。一层不变,固步自封,只会陷入价格战的同质化竞争中,永远无法取得商业上的巨大成功","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]},{"title":"以独特的理念征服世人","slug":"互联网+/以独特的理念征服世人_乔布斯","date":"2018-04-06T06:36:36.000Z","updated":"2018-07-11T06:08:24.000Z","comments":true,"path":"2018/04/06/互联网+/以独特的理念征服世人_乔布斯/","link":"","permalink":"https://ilifexiao.github.io/2018/04/06/互联网+/以独特的理念征服世人_乔布斯/","excerpt":"","text":"互联网+一、乔布斯:以独特的理念征服世人1.1 创新需要新想法、新手段:创新启示:作为一个企业,前进的方向便是,那些在脑海中一闪而过的灵感。敢于用属于自己的新想法来与市场相较量,并坚持不懈。 1.2 简约才能铸造永恒简化一切不需要的东西需要非常大的勇气 斯蒂夫-乔布斯说:”大家认为专注的意思是同意将精力都放在必须专注的事物上,但这不全面。它还意味着要拒绝数以百计的其他好创意。你必须精挑细选” 创新启示:用户的真实需求,简单易用的产品 1.3 创新也要借鉴别人知道什么是有价值的,什么是没有价值的,哪些是值得借鉴学习的,哪些是有没借鉴意义的。 能够和自己的产品结合起来,在借鉴的基础上做到创新,在进一步 创新启示:固步自封并不能赢得市场,创新有时也要借鉴他人。能够判断出其价值所在 1.4 创新可以创造奇迹技术再好,如果没有复合消费者需求的产品,没有配套的商业模式,或者很多技术态超前或者配套不合适,那么也会失败的。 乔布斯的创意不是纯技术层面的,而是科技与人文的碰撞,是最接近任性与广大消费者需求的创意 任何技术与产品服务的对象都是人,为创新而创新,为技术而技术都是不可取的,唯有把人放在创新的第一位,才不会在创新的道路上走偏、走错 创新启示:这是一个创意经济的时代,创意可以带来巨大的作用 1.5 细节是创新的突破口在乔布斯看来,越是小事月不能轻易的放过,一个开始不起眼的小细节往往可能就是一个崭新的创意切入口。 创新启示:细节决定成败 1.6 用人,找创新人才,用人才创新个人的价值观是否一致更为重要 两个方面:正如标题所述 创新启示:一个企业最重要的是人才,具有创造力的人才又是企业的宝贵财富 1.7 敢于想象,没什么是不可能的 爱因斯坦:”想象力远比知识来的更重要” 你必须在所有人和你设定好的界限之外思考,这就是苹果创新的秘密 能够做自己喜欢的事情 截至2014年11月乔布斯在产品开发过程中的专利就有458项 想要创新,就要允许自己异想天开,就要善于保持一颗初心,始终用富有童真的眼光区看待这个世界,打破一切世俗形成的条条框框与思维定势,来一个彻彻底底的头脑风暴,让我们的大脑接受洗礼,只有这样,我们才用可能像乔布斯那样拥有超强的发散思维,像诗人一样纯真,像幻想家一样想象,并最终用想象个创新工作指明前进的方向 创新启示: 乔布斯:”你一定不要按照客户所提出的要求来设计,要按照自己的想法走,等你按照客户的要求设计出来了,他们的要求也改变了” 当你有足够的创新想法时,就一定要努力动手实践,因为成功就在胜利的彼岸","categories":[{"name":"读书笔记","slug":"读书笔记","permalink":"https://ilifexiao.github.io/categories/读书笔记/"}],"tags":[{"name":"互联网+","slug":"互联网","permalink":"https://ilifexiao.github.io/tags/互联网/"}]}]}