- 浏览: 2473821 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (574)
- Book (62)
- Architecture (6)
- Java (39)
- Taobao (41)
- Distributed (4)
- Life (72)
- Database (7)
- Spring (16)
- Photography (15)
- Bicycle (41)
- Test (20)
- jBPM (8)
- Business (12)
- Movie (3)
- Ajax (15)
- Code (7)
- Eclipse (96)
- VIM (2)
- Music (6)
- Groovy (10)
- AutoHotKey (3)
- Dorado (10)
- Maven (7)
- Scrum (5)
- English (20)
- Financial (12)
- OSGi (3)
- Other (4)
- Tool (6)
- Browser (1)
- PPT (1)
- Project Management (4)
- Agile (6)
- Nosql (1)
- Search engine (6)
- Shell (2)
- Open Source (4)
- Storm (10)
- Guava (3)
- Baby (1)
- netty (1)
- Algorithm (1)
- Linux (1)
- Python (2)
最新评论
-
roy2011a:
https://github.com/ebottabi/sto ...
storm的序列化问题及与spring的结合方式 -
roy2011a:
能抗能打 写道哥们儿,你好!能共享下那个storm与sprin ...
storm的序列化问题及与spring的结合方式 -
Alick1:
兄弟,你之前是不是在深圳的正阳公司呆过啊?
storm的ack和fail -
liuleixwd:
先点个赞,写的非常好!有个问题请教下,如果我再bolt里不用e ...
storm的ack和fail -
yao-dd:
solr的facet查询
距离第一次看鲍勃大叔的"敏捷开发实践与模式"那本书已经有好多年了, 与那本书相比, 这本书相对来说更强调细节, 如果前一本书强调从大的方面, 比如从设计上, 从方法学上如何写出好的程序, 那么这一本书则是来强调从类的结构, 方法的布局, 变量的命名上阐述如何写出好的代码. 这本书基本上可以和kent back的"实现模式"那本书相提并论, 不过在有些理论上让我们从其他的方面看到了为什么, 如何写出好的代码. 另外这本书也让我明白了很多长期以来一些让我很纠结的原则, 比如一个方法只应该做一件事, 那么一个函数里面包含多个步骤, 每个步骤都做一件事, 那么多个步骤加在了一起岂不是做了多件事么? 而鲍勃大叔很好的解释了这个问题: 处于一个方法中同一抽象层级的多件事可以认为是一件事. 只有一个方法中同时处理了处于不同抽象层次的事物才违反了这个原则.
下面是一些笔记
有意义的命名
如果每次check in时, 代码都比check out时干净, 那么代码就不会腐坏
选个好名字是要花时间的, 但是省下来的时间比花掉的多. 一旦发现又更好的名称, 就换掉旧的.
变量, 函数或类的名称应该已经回答了所有的大的问题
如果名称需要注释来补充, 那就不算是名副其实.
好代码的演变:
第一个版本:
List<int[]> theList; public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>(); for (int[] x : theList) { if (x[0] == 4) { list1.add(x); } } return list1; }
第二个版本:
private static final int FLAGGED = 4; private static final int STATUS_VALUE = 0; List<int[]> gameBoard; public List<int[]> getFlaggedCells() { List<int[]> flaggedCells = new ArrayList<int[]>(); for (int[] cell : gameBoard) { if (cell[STATUS_VALUE] == FLAGGED) { flaggedCells.add(cell); } } return flaggedCells; }
最终的版本
class Cell { int status; private static final int FLAGGED = 4; boolean isFlagged() { return status == FLAGGED; } } List<Cell> gameBoard; public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<Cell>(); for (Cell cell : gameBoard) { if (cell.isFlagged()) { flaggedCells.add(cell); } } return flaggedCells; }
别用accountList来指称一组账号, 除非它真的是List类型, 用accountGroup或bunchOfAccounts, 甚至直接是accounts更好一些.
提防使用不同之处较小的名称. 避免混淆
废话是另外一种没有意义的区分, 假设你有一个Product类, 如果还有一个ProductInfo或者ProductData类, 那么它们的名称虽然不同, 意思却无区别. info和data就像a, an, the一样, 是意义含混的废话.
使用读得出来的名称.
单字母名称和数字常量有一个问题, 就是很难在一大篇文字中找出来.
单字母名称仅用于短方法中的本地变量, 名字长短应与其作用域大小相对应
类名和对象名应该是名词或者名词短语, 类名不应是动词.
重载构造器时, 使用描述了阐述的静态工厂方法名.
如果不能用程序员熟悉的术语给手头的工作命名, 就应该采用从涉及问题领域的名称. 至少负责维护代码的程序员就能去请教领域专家了.
添加有意义的语境, 可以添加前缀addrFirstname, addrLastName, addrState等, 以此提供语境, 至少, 读者会明白这些变量是某个更大结构的一部分. 当然更好的方案是创建名为Address的类, 这样, 即使是编译器也会知道这些变量隶属于某个更大的概念了.
不要添加没用的语境, 只要短名称足够清楚, 就要比长名称好.
取好名字最难的地方在于需要良好的描述技巧和共有的文化背景, 与其说这是一种技术还不如说是一种艺术(修辞学).
函数
函数只应该做一件事. 如果函数只是做了该函数名下同一抽象层上的步骤, 则函数还是只做了一件事, 编写函数毕竟是为了把大一些的代码拆分为另一抽象层上的一系列步骤
如何判断一个函数是做了一件事还是多件事, 可以用简洁的TO(为了..., 要...)起头来描述这个函数
要判断函数是否不止做了一件事, 还有一个办法,就是看是否能再拆出一个函数, 该函数不仅只是单纯地重新诠释其实现.
要确保函数只做一件事, 函数中的语句就要在同一抽象层级上.
一般情况下, 我们需要在每个函数后面跟着下一抽象层级的函数, 这样做阅读起来就比较有顺序和层次.
程序就像是一系列TO(为了..., 要...)起头的段落, 每一段都描述当前抽象层级, 并引用位于下一抽象层级的后续TO起头段落.
对于switch语句, 我的原则是如果只是出现一次, 用于创建多态对象, 而且隐藏在某个继承关系中, 在系统其它部分看不到, 就还能容忍, 当然也要就事论事, 有时候我也会部分或者全部违反这条原则.
函数越短小, 功能越集中, 就越便于取个好名字
别害怕长名称, 长而且具有描述性的名称, 要比短而令人费解的名称好, 长而具有描述性的名称, 要比描述性的长注释好.
命名方式要保持一致, 使用与模块名一脉相承的短语, 名词和动词给函数命名.
最理想的参数数量是0, 其次是1, 然后是2, 应尽量避免3, 3个以上的除非有特殊的理由.
参数与函数名处于不同的抽象层级, 它要求你了解目前并不特别重要的细节.
从测试的角度来看, 参数甚至更叫人为难.
输出参数比输入参数还要更敢于理解.
如果函数要对输入参数进行转换操作, 转换结果就该体现为返回值.
标识参数丑陋不堪, 向参数传入布尔值简直就是骇人听闻的做法. 这样做方法签名立刻变得复杂起来, 大声宣布本函数不止做了一件事, 如果表示为true会这样做, 表示为false会那样做.
如果函数看起来需要两个, 三个或三个以上的参数, 就说明其中一些参数应该封装为类了.
函数和参数应该形成一种非常良好的动名词形式, 比如assertEqual改成assertExpectEqualsActual会好很多, 虽然名称长了些, 但是更明确.
普遍而言, 应该尽量避免使用输出参数, 如果函数必须要修改某种状态, 就修改所属对象的状态吧.
比如这样的方法:private void appendFooter(StringBuffer report)
可以改为:report.appendFooter()
函数要么做什么事, 要么回答什么事, 但二者不可得兼(split query and command)
如果使用异常替代返回错误码, 错误处理代码就能从主路径代码中分离出来, 得到简化.
比如这样的代码
if (deletePage(page) == E_OK){ if (deleteReference(page.getName()) == E_OK){ if (deleteKey(page.getName().getKey())){ doSomething... }else{ log... } }else{ log... } }else{ log... }
更清晰的代码应该是这样:
try{ deletePage(page) deleteReference(page.getName()) deleteKey(page.getName().getKey()) }catch(Exception e){ log... }
try/catch代码丑陋不堪, 他们搞乱了代码结构, 把错误处理与正常流程混为一谈, 最好把try和catch代码块的主题部分抽离出来, 另外形成函数.
函数应该只做一件事, 错误处理就是一件事, 因此, 处理错误的函数不该做其他事.
使用异常替代错误码, 新异常就可以从异常类派生出来, 无需重新编译或重新部署.
重复可能是软件中一切邪恶的根源.
我们赞成结构化编程的目标和规范, 但对于小函数, 这些规则助益不大, 只有在大函数中, 这些规则才会有明显的好处.
只要函数保持短小, 偶尔出现的return, break或者continue语句并没有坏处, 甚至更具有表现力.
我并不从一开始就按照规则写函数, 我想没人能做到.
大师级程序员把系统当作故事来讲, 而不是当作程序来写.
注释
注释的恰当用法是弥补我们在用代码表达意图时遭遇的失败.
如果你发现自己需要写注释, 再想想看是否有办法翻盘, 用代码来表达, 每次用代码来表达你就该夸奖一下自己. 每次写注释, 你应该感受到你在表达能力上的失败.
写注释的常见动机之一是糟糕的代码的存在.
与其花时间编写解释你搞出的糟糕的代码的注释, 不如花时间清洁那堆糟糕的代码.
唯一真正好的注释是你想办法不去写的注释.
用于警告其他程序员会出现某种后果的注释是有用的.
TODO是一种程序员认为应该做, 但由于某些原因目前还没做的工作
如果你在编写公共的API, 就该为他编写良好的javadoc
坏注释都是糟糕代码的支撑或接口
如果你决定写注释, 就要花必要的时间确保写出最好的注释.
所谓每个函数都要有javadoc或者每个变量都要有注释的规矩全然是愚蠢可笑的.
能用函数或变量时, 就别用注释.
短函数不需要太多的描述. 为只做一件事的短函数选个好名字, 通常要比写函数头注释要好.
格式
紧密相关的代码应该互相靠近
相关函数, 如果某个函数调用了另外一个, 就应该把它们放在一起, 而且调用者应该尽量放在被调用者上面. 这样, 程序就有了自然的顺序. 若坚定的遵循这条约定, 读者就能够确定函数声明总会在其调用后很快出现.
概念相关. 概念相关的代码应该放在一起. 相关性越强, 彼此之间的距离就该越短.
代码的组织上, 应该像报纸一样, 最重要的概念先出来, 尽量以包含最少细节的方式表述它们, 底层细节最后出来.
尽量保持代码行短小, 不过死守80个字符有些僵化.
团队规则. 我们想要软件拥有一以贯之的风格. 我们不想让它想的是由一大票意见向左的个人所写成.
对象和数据结构
过程式代码便于在不改动既有数据结构的前提下添加新函数; 面向对象代码便于在不改动既有函数的前提下添加新类. 换言之. 过程式代码难以添加新数据结构, 因为必须修改所有函数, 面向对象代码难以添加新函数, 因为必须修改所有类. // 没看懂:(
对于面向对象较难的事, 对于过程式代码却较容易, 反之亦然.
方法不应调用由任何函数返回的对象的方法
Active Record是一种特殊的DTO, 它们是拥有javabean式的数据结构, 同时拥有类似save和find这样的方法, 它是一种数据库表或其他数据源的直接翻译
对象暴露行为, 隐藏数据.
错误处理
错误处理很重要, 但如果他搞乱了代码逻辑, 就是错误的做法.
别返回null值, 别传null值, 在大多数编程语言中, 没有良好的方法能对付由于调用者意外传入的null值, 事已至此, 恰当的做法是禁止传入null值, 这样你在编程的时候, 就会时时记住参数列表中的null值意味着出问题了.
如果将错误处理隔离看待, 独立于主要逻辑之外, 就能写出强固而整洁的代码, 而做到这一步, 我们就能够单独处理它, 也能极大的提升了代码的可维护性.
单元测试
单元测试三要素: 可读性, 可读性和可读性.
好的测试一般遵从构造-操作-检验(build-operate-check)模式, 每个测试都清晰分为三个环节, 第一个环节构造测试数据, 第二个环节操作测试数据, 第三个环节检验操作是否得到期望的结果.
单个测试中的断言数量应该最小化
类
公共函数应该跟在变量列表之后, 我们喜欢把由某个公共函数调用的是有工具函数紧随在该公共函数后面. 这符合了自顶向下原则, 让程序读起来就像一片报纸文章.
类名应该描述其职责, 实际上命名正是判断类的长度的一个手段, 如果无法为某个类命名以精确的名称, 这个类大概就太长. 类名越含混, 该类越有可能拥有过多的权责.
我们也应该能够用大概25个单词简要描述一个类, 且不用"if, and, or, but"等词汇.
类和模块应该有且只有一条加以修改的理由.(单一职责原则SRP)
类应该只有少量的实体变量, 类中的每个方法都应该操作一个或多个这种变量. 通常而言, 方法操作的变量越多, 就越粘聚到类上, 如果一个类中的每个变量都被每个方法所使用, 则该类具有很大的内聚性.
一般来说, 创建这种极大化类聚类是既不可取也不可能的; 另一方面, 我们希望内聚性保持在较高位置. 内聚性高, 意味着类中的方法和变量互相依赖, 互相结合成一个逻辑体.
当类丧失了内聚性, 就拆分它.
将大函数拆分为许多小函数, 往往也是将类拆分为多个小类的时机.
为了修改而组织, 将修改隔离.
系统
将系统的构造与使用分开
迭进
软件项目的主要成本在于长期维护. 为了在修改时尽量降低出现缺陷的可能性, 很有必要理解系统是做什么的, 当系统变得越来越复杂, 开发者就需要越来越多的时间来理解它, 而且也极有可能误解. 所以, 代码应当清晰地表达其作者的意图.
逐步改进
编程是一种技艺胜于科学的东西. 要编写整洁代码, 必须先写肮脏代码, 然后再清理它.
写出好文章是一个逐步改进的过程.
毁坏程序的最好方法之一就是以改进之名大动其结构, 有些程序永远不能从这种所谓的"改进"中恢复过来.
放进拿出是重构过程中常见的事. 小步和保持测试通过, 意味着你会不断移动各种东西, 重构有点像是解魔方. 需要经过许多小步骤, 才能达到较大目标, 每一部都是下一步的基础.
总结
如果注释描述的是某种充分自我描述了的东西, 那么注释就是多余的.
注释应该谈及代码自身没提到的东西.
如果要编写一条注释, 就花时间保证写出最好的注释.
只与细节相关的常量, 变量或工具函数不应该在基类中出现, 基类应该对这些东西一无所知.
如果看到基类提到派生类名称, 就可能发现了问题. 通常来说, 基类对派生类应该一无所知.
每个选择算子参数将多个函数绑定到了一起, 选择算子参数只是一种避免把大函数切分为多个小函数的偷懒做法. 选择算子不一定是boolean类型, 可能是枚举, 整数或任何用于选择函数行为的参数, 使用多个函数, 通常优于向单个函数传递某些代码来选择函数行为.
通常应该倾向于选用非静态方法, 如果有疑问, 就是用非静态函数, 如果的确需要静态函数, 确保没机会打算让它有多态行为.
如果你必须查看函数的实现或者文档才知道它是做什么, 就应该换个更好的函数名, 或者重新安排功能代码, 放到有较好名称的函数中.
在你认为自己完成了某个函数之前, 确认自己理解了它是如何工作的. 通过全部测试还不够好. 你必须知道解决方案是正确. 而获得这种知识和理解的最好途径, 往往是重构函数, 得到某种整洁而足够具有表达力, 清楚呈现如何工作的东西.
SECONDS_PRE_DAY是个好名字
魔术字不仅仅是说数字, 它泛指任何不能自我描述的符号.
if (shouldBeDelete(timer))
要好于:
if (timer.hasExpired() && !timer.isRecurrent())
否定式要比肯定式难明白一些, 所以尽量将条件表达式表示为肯定方式.
常常有必要使用时序耦合, 但你不应该掩饰它.
public void dive(String reason){ saturateGradient(); reticulateSplines(); diveForMoog(reason); }
更好的写法是:
public void dive(String reason){ Gradient gradient = saturateGradient(); List<Spline> splines = reticulateSplines(gradient); diveForMoog(splines, reason); }
这样就通过创建顺序队列暴露了时序耦合. 每个函数都产生出下一个函数所需的结果, 这样一来就没理由不按顺序调用了.
拆分不同抽象层级是重构的最重要功能之一, 也是最难做的一个.
通常我们不想让某个模块了解太多其协作者的信息, 更具体的说, 如果A与B协作, B与C协作, 我们不想让使用A的模块了解C的信息.
现在的enum已经可以放心使用了, 别再用那个public static final int 老花招了, 那样做就int的意义就丧失了. 而enum则不然, 因为它们隶属于有名称的枚举. 而且仔细研究enum的语法, 它可以拥有方法和字段, 从而成为能比int提供更多表达力和灵活性的强力工具.
不要取具体实现的名字; 取反映类或函数抽象层级的名称, 这样做不容易, 人们擅长于混杂抽象层级, 每次浏览代码, 你总会发现有些变量的名称层级太低. 你应该层级为之改名.
比如一个Modem接口:
public interface Modem{ ... String getConnectionPhoneNumber(); }
因为有些Modem可能不是采用电话拨号的, 比如宽带, 这个方法不具有抽象性, 因此需要重命名, 比如采用getConnectionLocator
名称长度与作用范围的广泛度相关. 对于较小的作用范围, 可以用较短的名称, 而对于较大作用范围就该用较长的名称.
名称应该说明其副作用.
比如这样的方法:
public ObjectOutputStream getOos(){ if (m_oos==null){ m_oos = new ObjectOutputStream(m_stocket.getOutputStream()); } return m_oos; }
这里不只是获取一个oos, 如果oos不存在, 还会创建一个. 所以更好的名称是: createOrReturnOos
缺陷倾向于扎堆, 在某个函数中发现一个缺陷时, 最好全面测试那个函数, 你可能发现缺陷不止一个.
现代处理器拥有一种通常称为比较交换(Compare and Swap, CAS)的操作, 这种操作类似于数据库中的乐观锁定, 而其同步版本则类似于保守锁定.
关键字synchronized总是要求上锁, 即便第二个线程并不更新同一个值时也是如此. 尽管这种固有锁的性能一直在提升, 但代价依然昂贵.
非上锁版本假定多个线程通常并不频繁改同一个值, 导致问题产生. 他高效地侦测这种情形是否发生, 并不断滴尝试, 直至更新成功, 这种侦测行为总比上锁来的划算, 在争用激烈的情况下也是如此.
当某个方法试图更新一个共享变量, CAS操作就会验证要赋值的变量是否保有上一次的已知值, 如果是, 就修改变量值, 如果不是, 则不会碰变量, 因为另一个线程正在试图更新变量值. 要更新数据的方法(通过CAS操作)查看是否修改并持续尝试.
int variableBeingSet void simulateNonBlockingSet(int newValue){ int currentValue; do{ currentValue = variableBeingSet; }while(currentValue != compareAndSwap(currentValue, newValue)); } int synchronized compareAndSwap(int currentValue, int newValue){ if (variableBeingSet == currentValue){ variableBeingSet = newValue; return currentValue; } return variableBeingSet; }
getNextOrNull这个方法名不错.
评论
您好:
请问“同一抽象层级”是什么意思?谢谢!
假如创建保存一篇博客文章需要经过以下步骤:
1)验证用户是否有权限
2)检查博客中是否有违禁字
3)将博客内容保存到存储系统中
4)发送相关的系统消息
5)返回提示信息
如果在一个类方法中处理了以上所有的这些内容, 但是实现这些操作的具体细节是放其他的模块来实现的, 那么以上这些调用都处于同一抽象层级, 如果这里将第三步中具体保存到存储系统中细节放在该方法中(比如创建连接, 构建提交参数, 执行保存的sql语句, 关闭连接), 则会出现一个方法中存在不同抽象层级的逻辑, 会导致逻辑不清晰
您好:
请问“同一抽象层级”是什么意思?谢谢!
发表评论
-
<异类>读书笔记
2013-03-06 07:54 0成功者能够获得更多的机会,从而能变得更为成功。税收愈减免,富人 ... -
《python学习手册》学习笔记
2013-03-11 22:25 3474python格式化传参数非常赞,用数字标明位置,值得java学 ... -
<万历十五年>读书笔记
2013-03-11 22:27 1619在网上下了一个电子书, 但是貌似跟万历十五年没啥关系, 都是讨 ... -
《鸟哥的linux私房菜》读书笔记(部分)
2013-03-11 22:27 2068x86是一种微机系统硬件架构,另一种是苹果的mac的架构 l ... -
《你的灯亮了吗》读书笔记
2013-03-06 07:20 1522这是一本原本写给程序员的书 本书的四个问题: 搞清问题的来源 ... -
《小狗钱钱》读书笔记
2013-03-06 07:17 1482一本非常不错的理财学习入门书, 以童话的形式, 儿童的思维方式 ... -
《我的奋斗》读书笔记
2012-04-14 22:03 2077文字写的很幽默, 故事也基本都是一些平常人的故事,看到了一个特 ... -
《Java Performance》书评
2012-01-15 18:32 2967原文: http://java.dzone.com/rev ... -
《程序员应该知道的97件事》读书笔记
2012-01-15 18:36 2389一本关于写代码的文 ... -
《影响力》读书笔记
2011-11-05 14:47 1836从书名上很可能以为 ... -
《浪潮之巅》读书笔记
2011-11-05 14:44 1375作为一个中国人通过分析硅谷高科技公司的一系列传奇, 总结出这 ... -
《黑客与画家》读书笔记
2011-11-05 13:37 1822以前看过《rework》, 觉得是每一个小型创业公司的创业宝 ... -
《乔布斯传》读书笔记
2011-10-18 08:53 2854在ipad上看完了这本书, 写的还不错, 里面没有无聊的八 ... -
《细说Java》读书笔记
2011-10-05 15:01 1998国人写的, 感觉是一 ... -
《敏捷估计与规划》读书笔记
2011-10-05 12:08 3181这本书断断续续看了很长时间, 内容非常不错, 基本涵盖了sc ... -
《怪诞心理学》读书笔记
2011-10-05 09:44 1828既然是怪诞, 那么整本书涉及的内容并不是我们平常司空见怪的一 ... -
《番茄工作法图解》读书笔记
2011-09-28 09:02 2393番茄工作法是时间管 ... -
《Java开发超级工具集》读书笔记
2011-09-28 08:59 2102"工欲善其事必先利其器", 在平时的开发 ... -
《敏捷迭代开发管理者指南》读书笔记
2011-09-24 13:09 2220这是一本关于迭代开发 ... -
《解析极限编程》读书笔记
2011-09-24 13:03 1791不知道是kent beck的语 ...
相关推荐
基于智能温度监测系统设计.doc
包括userCF,itemCF,MF,LR,POLY2,FM,FFM,GBDT+LR,阿里LS-PLM 基于深度学习推荐系统(王喆)
2023-04-06-项目笔记-第三百五十五阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.353局变量的作用域_353- 2024-12-22
和美乡村城乡融合发展数字化解决方案.docx
基于Python的深度学习图像识别系统是一个利用卷积神经网络(CNN)对图像进行分类的先进项目。该项目使用Python的深度学习库,如TensorFlow,构建和训练一个模型,能够自动识别和分类图像中的对象。系统特别适合于图像处理领域的研究和实践,如计算机视觉、自动驾驶、医疗影像分析等。 项目的核心功能包括数据预处理、模型构建、训练、评估和预测。用户可以上传自己的图像或使用预定义的数据集进行训练。系统提供了一个直观的界面,允许用户监控训练进度,并可视化模型的性能。此外,系统还包括了一个模型优化模块,通过调整超参数和网络结构来提高识别准确率。 技术层面上,该项目使用了Python编程语言,并集成了多个流行的机器学习库,如NumPy、Pandas、Matplotlib等,用于数据处理和可视化。模型训练过程中,系统会保存训练好的权重,以便后续进行模型评估和预测。用户可以通过简单的API调用,将新的图像输入到训练好的模型中,获取预测结果。
拳皇97.exe拳皇972.exe拳皇973.exe
基于python和协同过滤算法的电影推荐系统 基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法的电影推荐系统基于python和协同过滤算法
DEV-CPP-RED-PANDA
Python语言求解旅行商问题,算法包括禁忌搜索、蚁群算法、模拟退火算法等。
pdfjs 用于在浏览器中查看/预览/打印pdf。 pdfjs 2.5.207 支持firefox/chrome/edge/ie11以上版本。 如果需要支持旧版本浏览器,可以使用这个,是未修改过的原版,支持打印和下载按钮。亲测有效。 pdf 4.9.155分两个包: pdfjs-4.9.155-dist.zip pdfjs-4.9.155-legacy-dist.zip
建设项目现场高温人员中暑事故应急预案
数据结构上机实验大作业-线性表选题.zip
【资源说明】 基于高德地图的校园导航全部资料+详细文档+高分项目.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
【静态站群程序视频演示,只有视频,不含程序,下载须知】【静态站群程序视频演示,只有视频,不含程序,下载须知】全自动批量建站快速养权重站系统【纯静态html站群版】:(GPT4.0自动根据关键词写文章+自动发布+自定义友链+自动文章内链+20%页面加提权词)
9.30 SWKJ 男头7张+女头2张.zip
项目已获导师指导并通过的高分毕业设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 项目都经过严格调试,确保可以运行!可以放心下载 技术组成 语言:java 开发环境:idea、vscode 数据库:MySql5.7以上 部署环境:maven 数据库工具:navicat
一个通过单片机在各种屏幕上显示中文的解决方案.7z
图像
一、用户管理功能 用户注册与登录 学生注册:学生可以通过手机号、邮箱、社交账号等方式注册,填写个人信息(如姓名、年龄、学校等)。 家长/监护人账户:支持家长/监护人注册并管理学生账户,查看学习进度和成绩。 教师账户:教师可以注册并设置个人资料,上传资质认证文件。 管理员账户:管理员负责整个系统的管理,包括用户管理、课程管理、平台设置等。 用户权限管理 角色权限:系统根据用户类型(学生、家长、教师、管理员)分配不同权限,确保信息安全。 家长监督:家长可以查看子女的学习进度、成绩和教师反馈,参与学习监督。 个人资料管理 用户可以在个人中心更新基本信息,设置个人头像、联系方式、密码等。 支持学籍信息的维护,例如学生的年级、班级、课程历史等。 二、课程管理功能 课程设置 课程创建与编辑:教师或管理员可以创建和编辑课程内容,上传课件、视频、文档等教学材料。 课程分类:根据学科、年级、难度等维度进行课程分类,方便学生浏览和选择。 课程排课:管理员可以设置课程的时间表、教学内容和授课教师,并调整上课时间和频率。 课程安排与通知 课程预约:学生可以在线选择并预约感兴趣的课程,系统根据学生的时
内容概要:本文档介绍了英特尔2021年至2024年的网络连接性产品和智能处理单元(IPU)的战略和技术路线图。涵盖了从10GbE到200GbE的不同系列以太网适配器的特性、性能和发布时间。详细列出了各个产品的关键功能,如PCIe接口、安全特性、RDMA支持等。同时,介绍了IPU的发展计划,包括200G、400G和800G的不同代次产品的性能提升和新的功能特点。 适合人群:从事网络工程、数据中心管理、IT架构设计的专业技术人员。 使用场景及目标:本文档主要用于了解英特尔未来几年在以太网适配器和IPU领域的技术和产品规划,帮助企业在采购和部署网络设备时做出决策。同时,为研究人员提供最新技术发展趋势的参考。 其他说明:文档内容涉及的技术细节和时间表可能会有变动,请以英特尔官方发布的最新信息为准。