[{"data":1,"prerenderedAt":1472},["ShallowReactive",2],{"post:\u002Fposts\u002Fswdesign\u002Fsw-design-notes-21":3,"posts:ordered":1170},{"id":4,"title":5,"body":6,"category":1151,"cover":1152,"date":1153,"description":1154,"extension":1155,"featured":1156,"meta":1157,"navigation":1158,"path":1159,"seo":1160,"series":1161,"seriesOrder":1162,"stem":1163,"tags":1164,"__hash__":1169},"posts\u002Fposts\u002FswDesign\u002Fsw-design-notes-21.md","软件分析与设计笔记 21：UML：类图与顺序图",{"type":7,"value":8,"toc":1121},"minimark",[9,16,21,26,29,40,43,47,52,55,123,127,134,138,148,152,156,159,181,188,192,212,222,225,235,242,279,283,287,368,375,448,452,458,516,519,571,575,581,587,591,595,601,621,624,666,670,673,679,686,690,697,711,715,728,734,741,745,748,762,768,775,778,809,812,890,893],[10,11,12],"blockquote",{},[13,14,15],"p",{},"这是我在学习软件分析与设计时整理的系列笔记。概念部分是我按自己的理解写的，示例与图示都是自己编、自己画的，参考的是 UML 规范这类公开资料。理解有偏差的地方欢迎指出。",[10,17,18],{},[13,19,20],{},"本篇沿用贯穿案例「片区家电维修派单系统」：工程师上门、仓管备料、客服派单。如果你是从 08 篇读过来的，角色和实体都是同一批。",[22,23,25],"h2",{"id":24},"_0-为什么需要一种共同的画法","0 为什么需要一种共同的画法",[13,27,28],{},"一个五人团队，如果每个人用自己的方式表达「一张工单有多条配件明细」，就会出现五种画法：有的画箭头、有的写文字、有的直接画表格。讨论的力气全花在「你画的这个箭头什么意思」上。",[13,30,31,35,36,39],{},[32,33,34],"strong",{},"UML（Unified Modeling Language）"," 的价值就在这里：",[32,37,38],{},"它是一套约定的符号","，让「这张图在说什么」不再需要额外解释。",[13,41,42],{},"注意关键词是「符号」。UML 不规定你怎么做设计，只规定你怎么把设计画出来。",[22,44,46],{"id":45},"_1-uml-在流程里的位置","1 UML 在流程里的位置",[48,49,51],"h3",{"id":50},"_11-各工作流常用哪些图","1.1 各工作流常用哪些图",[13,53,54],{},"UML 的各类图并不是都用在同一个阶段，它们对应不同的工作流：",[56,57,58,71],"table",{},[59,60,61],"thead",{},[62,63,64,68],"tr",{},[65,66,67],"th",{},"工作流",[65,69,70],{},"常用的图",[72,73,74,83,91,99,107,115],"tbody",{},[62,75,76,80],{},[77,78,79],"td",{},"业务建模（business modeling）",[77,81,82],{},"用例图（use case diagram）、活动图",[62,84,85,88],{},[77,86,87],{},"需求（requirements）",[77,89,90],{},"用例图、活动图",[62,92,93,96],{},[77,94,95],{},"分析（analysis）",[77,97,98],{},"类图（class diagram）、顺序图",[62,100,101,104],{},[77,102,103],{},"设计（design）",[77,105,106],{},"类图、顺序图",[62,108,109,112],{},[77,110,111],{},"实现（construction \u002F implementation）",[77,113,114],{},"类图（贴近代码的细化）",[62,116,117,120],{},[77,118,119],{},"测试（testing）",[77,121,122],{},"用例图、顺序图（推导测试场景）",[48,124,126],{"id":125},"_12-同一张图会反复出现","1.2 同一张图会反复出现",[13,128,129,130,133],{},"看这张表能发现一件事：",[32,131,132],{},"同一个类型的图会反复出现，只是细节程度不同","。分析阶段画「工单」这个概念，设计阶段可能画到「工单表对应的实体类」。所以不要把「这张类图到底算分析还是设计」当成是非题。",[48,135,137],{"id":136},"_13-这一篇的两个主角","1.3 这一篇的两个主角",[13,139,140,143,144,147],{},[32,141,142],{},"类图管静态结构","（有哪些类、彼此什么关系），",[32,145,146],{},"顺序图管动态交互","（某一次操作里，这些对象按什么顺序互相调用）。两者是一对：先画顺序图把交互想清楚，再从顺序图机械导出类图（笔记 22 会详细讲这个导出过程）。",[22,149,151],{"id":150},"_2-类图三格结构与可见性","2 类图：三格结构与可见性",[48,153,155],{"id":154},"_21-类符号的三格","2.1 类符号的三格",[13,157,158],{},"类图（class diagram）里最基本的元素是类符号（class symbol），它由三格组成：",[160,161,162,169,175],"ol",{},[163,164,165,168],"li",{},[32,166,167],{},"类名","；",[163,170,171,174],{},[32,172,173],{},"属性列表（attribute list）"," —— 对象需要记住的状态；",[163,176,177,180],{},[32,178,179],{},"操作（operation）"," —— 对象能提供的行为。",[13,182,183],{},[184,185],"img",{"alt":186,"src":187},"类图符号特写：左边是分三格的类符号，自上而下是类名 WorkOrder、属性列表（含 -id : String、-status : Status 这类带可见性的写法）、操作列表；右边标出五种关系符号——依赖（虚线箭头）、关联（实线，可带重数 1 与 *）、聚合（空心菱形）、组合（实心菱形）、继承（空心三角指向父类），每个符号下注明 draw.io 的搜索关键词","\u002Fimages\u002Fsw-design-notes-21-class-sequence-symbols.svg",[48,189,191],{"id":190},"_22-可见性在传达什么","2.2 可见性在传达什么",[13,193,194,195,198,199,203,204,207,208,211],{},"属性前面可以标",[32,196,197],{},"可见性（visibility）","：",[200,201,202],"code",{},"-"," 表示 private（只有自己可见）、",[200,205,206],{},"+"," 表示 public（所有类可见）、",[200,209,210],{},"#"," 表示 protected（子类可见）。",[13,213,214,215,221],{},"这个符号看着是细节，但它其实在传达设计意图：",[32,216,217,218,220],{},"一个字段被标成 ",[200,219,206],{},"，等于宣布「任何人都能改它」"," —— 这在多数情况下都不是想要的结果（见笔记 20 关于封装的讨论）。",[13,223,224],{},"一个具体的写法示例（贯穿案例里的工单类）：",[226,227,232],"pre",{"className":228,"code":230,"language":231},[229],"language-text","WorkOrder\n- id : String\n- status : WorkOrderStatus\n- createdAt : Date\n+ assign(engineerId : String) : void\n+ close() : void\n","text",[200,233,230],{"__ignoreMap":234},"",[13,236,237,238,241],{},"注意类型的写法是 ",[200,239,240],{},"名字 : 类型","，冒号前后各一个空格；返回类型跟在参数括号后面再跟一个冒号。",[10,243,244],{},[13,245,246,249,250,253,254,257,258,260,261,263,264,267,268,267,271,274,275,278],{},[32,247,248],{},"画这一笔","：draw.io 搜 ",[200,251,252],{},"class","（UML 分类），拖入画布得到默认三格框，",[32,255,256],{},"双击任意一格","即可编辑。要让某个属性变成 ",[200,259,202],{},"，直接在格子里手打 ",[200,262,202],{},"。\n三格之间的横线 draw.io 会自动生成，不用自己画。\n官方型（",[200,265,266],{},"«entity»","、",[200,269,270],{},"«boundary»",[200,272,273],{},"«control»","）的加法是双击类名上方会出现一行 ",[200,276,277],{},"«»","，在里面填 entity。",[22,280,282],{"id":281},"_3-五种关系","3 五种关系",[48,284,286],{"id":285},"_31-符号与含义","3.1 符号与含义",[56,288,289,302],{},[59,290,291],{},[62,292,293,296,299],{},[65,294,295],{},"关系",[65,297,298],{},"UML 符号",[65,300,301],{},"含义",[72,303,304,315,326,341,354],{},[62,305,306,309,312],{},[77,307,308],{},"dependency",[77,310,311],{},"虚线 + 开放箭头",[77,313,314],{},"临时使用",[62,316,317,320,323],{},[77,318,319],{},"association",[77,321,322],{},"实线（可带重数 multiplicity）",[77,324,325],{},"长期持有引用",[62,327,328,331,338],{},[77,329,330],{},"aggregation",[77,332,333,334,337],{},"空心菱形（菱形在",[32,335,336],{},"整体","一侧）",[77,339,340],{},"部分可独立存在",[62,342,343,346,351],{},[77,344,345],{},"composition",[77,347,348,349,337],{},"实心菱形（菱形在",[32,350,336],{},[77,352,353],{},"部分随整体消亡",[62,355,356,359,365],{},[77,357,358],{},"inheritance",[77,360,361,362],{},"空心三角，",[32,363,364],{},"指向父类",[77,366,367],{},"is-a",[13,369,370,371,374],{},"五种关系里有三种在 draw.io 里特别难找（聚合、组合、继承），因为它们不在形状库里，而是",[32,372,373],{},"改线的端点样式","改出来的。这是画类图时最容易卡住的地方：",[10,376,377,390,431],{},[13,378,379,381,382,385,386,389],{},[32,380,248],{},"：先连一条普通实线（拖形状边缘的小箭头），然后",[32,383,384],{},"选中这条线","，右侧格式面板会出现 ",[200,387,388],{},"Line"," 一栏：",[391,392,393,411,421],"ul",{},[163,394,395,396,399,400,403,404,407,408,168],{},"继承 → ",[200,397,398],{},"Line Start"," 或 ",[200,401,402],{},"Line End"," 选 ",[32,405,406],{},"block\u002Fopen arrow"," 里的空心三角，并勾选 ",[200,409,410],{},"filled=0",[163,412,413,414,417,418,420],{},"聚合 → 端点选 ",[32,415,416],{},"diamond","，勾选 ",[200,419,410],{},"（空心）；",[163,422,423,424,426,427,430],{},"组合 → 端点选 ",[32,425,416],{},"，",[200,428,429],{},"filled=1","（实心）。",[13,432,433,434,436,437,440,441,444,445],{},"找不到就在格式面板按 ",[200,435,206],{}," 展开 ",[200,438,439],{},"Edit Style","，直接打 ",[200,442,443],{},"endArrow=block;endFill=0;","。",[32,446,447],{},"这一串记住比记菜单稳。",[48,449,451],{"id":450},"_32-每种关系落到-java-的写法","3.2 每种关系落到 Java 的写法",[13,453,454,455,198],{},"关键是",[32,456,457],{},"每种关系落到代码里都不一样",[56,459,460,469],{},[59,461,462],{},[62,463,464,466],{},[65,465,295],{},[65,467,468],{},"Java 里的典型写法",[72,470,471,482,490,498,508],{},[62,472,473,476],{},[77,474,475],{},"Association",[77,477,478,479],{},"字段持有集合，例如 ",[200,480,481],{},"List\u003CPart> parts",[62,483,484,487],{},[77,485,486],{},"Aggregation",[77,488,489],{},"集合字段，但元素由外部传入（构造参数或设置方法）",[62,491,492,495],{},[77,493,494],{},"Composition",[77,496,497],{},"集合字段，元素在整体内部创建与管理，不对外暴露",[62,499,500,503],{},[77,501,502],{},"Inheritance",[77,504,505],{},[200,506,507],{},"class UrgentOrder extends WorkOrder",[62,509,510,513],{},[77,511,512],{},"Dependency",[77,514,515],{},"出现在方法参数或局部变量里，不保留引用",[13,517,518],{},"贯穿案例里这五种都能找到对应：",[391,520,521,534,545,555,566],{},[163,522,523,525,526,529,530,533],{},[32,524,494],{}," —— ",[200,527,528],{},"WorkOrder"," 与 ",[200,531,532],{},"PartUsage","（工单里的配件消耗行）。配件消耗是随工单一起创建、一起删除的，单独存在没有意义；",[163,535,536,525,538,529,541,544],{},[32,537,486],{},[200,539,540],{},"Engineer",[200,542,543],{},"Skill","（技能）。工程师会换技能，技能本身不依附于人；",[163,546,547,525,549,529,551,554],{},[32,548,475],{},[200,550,528],{},[200,552,553],{},"Customer","。工单长期持有客户引用；",[163,556,557,525,559,529,562,565],{},[32,558,512],{},[200,560,561],{},"DispatchService",[200,563,564],{},"StockApi","。只在方法里调一次，不保留引用；",[163,567,568,570],{},[32,569,502],{}," —— 不存在。这个案例里没有真正的 is-a 关系 —— 这一点本身就是个结论，硬要找继承反而会造出笔记 25 讲的「被拒绝的馈赠」。",[48,572,574],{"id":573},"_33-符号不是装饰","3.3 符号不是装饰",[13,576,577,580],{},[32,578,579],{},"这些符号不是装饰","。把组合画成聚合，不只是图错了 —— 它会直接误导实现的人该怎么管理对象的生命周期。",[13,582,583,584,586],{},"举个具体的代价：如果 ",[200,585,532],{}," 被画成聚合，开发会认为「配件消耗行可以独立存在、可以让多张工单共享」，于是他建了一张独立表和一张多对多关联表。等到要按工单核销的时候，就不得不写一堆中间逻辑把这些行重新归到工单下面。",[22,588,590],{"id":589},"_4-顺序图三要素","4 顺序图：三要素",[48,592,594],{"id":593},"_41-三个基本元素","4.1 三个基本元素",[13,596,597,600],{},[32,598,599],{},"顺序图（sequence diagram）"," 描述对象之间的交互，纵向表示时间。三个基本元素：",[391,602,603,609,615],{},[163,604,605,608],{},[32,606,607],{},"生命线（lifeline）"," —— 参与这次交互的每个对象，用竖直虚线表示；",[163,610,611,614],{},[32,612,613],{},"消息（message）"," —— 对象之间的调用，用横向箭头表示，箭头方向就是调用方向；",[163,616,617,620],{},[32,618,619],{},"激活条（activation）"," —— 表示某段时间这个对象正在处理（收到消息到返回结果之间）。",[13,622,623],{},"顺序图的符号也在上面那张图里，和类图共用一套箭头样式：",[10,625,626,638],{},[13,627,628,249,630,633,634,637],{},[32,629,248],{},[200,631,632],{},"sequence","，或直接从 ",[200,635,636],{},"UML"," 分类拖出一组预置的生命线（它是一个组合好的形状，拖入后自带虚线与激活条）。",[391,639,640,643,650,659],{},[163,641,642],{},"改名：双击生命线顶部的矩形；",[163,644,645,646,649],{},"加消息：拖生命线边缘的小箭头连到对方，然后",[32,647,648],{},"双击连线中间","打字；",[163,651,652,653,655,656,168],{},"返回用虚线：选中消息线，",[200,654,388],{}," → 选 ",[200,657,658],{},"dashed",[163,660,661,662,665],{},"激活条如果没自动出现，右侧格式面板搜 ",[200,663,664],{},"activation","，或直接画一个细矩形叠上去。",[48,667,669],{"id":668},"_42-生命线的顺序是有讲究的","4.2 生命线的顺序是有讲究的",[13,671,672],{},"摆生命线不是随便排的。分析模型的顺序图有个约定俗成的顺序：",[226,674,677],{"className":675,"code":676,"language":231},[229],": Actor  |  : Boundary  |  : Control  |  : Entity…\n",[200,678,676],{"__ignoreMap":234},[13,680,681,682,685],{},"从左到右对应「谁发起 → 界面 → 协调 → 数据」。原因很实际：",[32,683,684],{},"消息箭头大部分是从左指向右的","，按这个顺序摆，交叉线最少，图最好读。笔记 22 会展开这三种对象的职责。",[48,687,689],{"id":688},"_43-它还能暴露职责错位","4.3 它还能暴露职责错位",[13,691,692,693,696],{},"顺序图有一个容易被忽略的优点：",[32,694,695],{},"它能暴露「谁该知道谁」这个问题","。如果一张顺序图里，界面对象直接调用了数据对象、又自己做了业务判断，那这张图本身就在提示职责分错了位置 —— 这正是笔记 22 要展开的内容。",[13,698,699,700,703,704,707,708,444],{},"在贯穿案例里有个现成的例子：如果「派单」顺序图里出现 ",[200,701,702],{},":DispatchForm"," 直接调用 ",[200,705,706],{},":Engineer.getSchedule()","，这张图就在告诉你：界面越过了控制器去拿数据。改法是中间补一个 ",[200,709,710],{},":DispatchController",[22,712,714],{"id":713},"_5-对象图object-diagram","5 对象图（object diagram）",[13,716,717,718,721,722,267,725,444],{},"类图描述「有哪些类」，",[32,719,720],{},"对象图（object diagram）"," 描述「某一时刻具体有哪些对象、它们的引用关系如何」，例如 ",[200,723,724],{},"工单A1091",[200,726,727],{},"张伟（工程师）",[13,729,730,731],{},"它用得比类图少，但在排查问题时很有用：",[32,732,733],{},"当你怀疑「这两个对象之间到底有没有关联」时，画一个对象图比读代码快。",[13,735,736,737,740],{},"判断什么时候用对象图，就看一句话：",[32,738,739],{},"你要回答的是「这一类东西之间什么关系」，还是「这两个具体的东西之间什么关系」","？前者用类图，后者用对象图。",[22,742,744],{"id":743},"_6-关于工具","6 关于工具",[13,746,747],{},"建模工具（modeling tool）很多，从在线工具到桌面工具都有。选的时候只需要看两点：",[391,749,750,756],{},[163,751,752,755],{},[32,753,754],{},"能不能正确表达 UML 符号","（尤其是四种菱形与三角）；",[163,757,758,761],{},[32,759,760],{},"改起来方不方便"," —— 需求阶段改图是常态，工具如果改一次要重画，你就会开始少改。",[13,763,764,765],{},"工具本身不影响设计质量：",[32,766,767],{},"用工具画得整齐，不等于关系画对了。",[13,769,770,771,774],{},"有一个很实际的检查方法：画完一张类图，",[32,772,773],{},"让另一个人只看图来写代码","。如果他写错了某个生命周期语义（比如把组合当聚合处理），那就是图没画对，不是你表达不清。",[22,776,777],{"id":777},"本节自测",[160,779,780,783,786,789,792,795,798,801],{},[163,781,782],{},"UML 规范规定了什么、又没有规定什么？",[163,784,785],{},"同一个类名在分析阶段和设计阶段，画的详细程度为什么不同？",[163,787,788],{},"聚合和组合在 Java 里的写法差别体现在哪？用贯穿案例里的工单与配件消耗举例说明。",[163,790,791],{},"顺序图的三个基本元素分别是什么？纵向代表什么？",[163,793,794],{},"什么情况下画对象图比读代码更有效？",[163,796,797],{},"在 draw.io 里画「空心三角」表示继承，你是怎么找到它的？为什么这个符号不在形状库里？",[163,799,800],{},"一张顺序图的四条生命线，按什么顺序摆？为什么？",[163,802,803,804,703,806,808],{},"如果「派单」顺序图里 ",[200,805,702],{},[200,807,706],{},"，这张图在提示什么问题？",[48,810,811],{"id":811},"参考答案",[160,813,814,820,823,841,847,854,874,880],{},[163,815,816,819],{},[32,817,818],{},"规定符号，不规定设计。"," UML 只规定「怎么把设计画出来」，不管你怎么做设计 —— 用不用继承、要不要分层，都是自己的判断（§0）。",[163,821,822],{},"因为关注点不同。分析阶段画「工单」这个概念本身（业务语义）；设计阶段要画到「工单表对应的实体类」（含字段类型、主键）。所以同一张图会反复出现，只是细节加深（§1.2）。",[163,824,825,828,829,832,833,529,835,837,838,840],{},[32,826,827],{},"聚合","：集合字段但元素由外部传入（构造函数\u002F setter）；",[32,830,831],{},"组合","：元素在整体内部创建、不对外暴露。本例：",[200,834,528],{},[200,836,532],{}," 是组合（配件消耗行随工单创建与删除），如果把 ",[200,839,532],{}," 画成聚合，开发会以为它可以独立存在、可被多张工单共享（§3.2 \u002F §3.3）。",[163,842,843,846],{},[32,844,845],{},"生命线、消息、激活条","。纵向是时间，从上往下读（§4.1）。",[163,848,849,850,853],{},"当你要回答的是 ",[32,851,852],{},"「这两个具体对象之间有没有关联」"," 时。类图只能回答「这一类之间能不能关联」，对象图能直接画出这一份实例的引用关系（§5）。",[163,855,856,857,860,861,863,864,867,868,870,871,873],{},"它不是形状库里的独立形状，而是",[32,858,859],{},"线的端点样式","：选中连线 → 格式面板 ",[200,862,388],{}," → 端点选 block\u002Fopen arrow → ",[200,865,866],{},"endFill=0","。也可以直接 ",[200,869,439],{}," 打 ",[200,872,443],{},"（§3.1 的画这一笔）。",[163,875,876,879],{},[200,877,878],{},": Actor | : Boundary | : Control | : Entity","。因为大部分消息箭头是从左指向右的，按这个顺序摆交叉线最少、图最好读（§4.2）。",[163,881,882,883,886,887,889],{},"它提示",[32,884,885],{},"职责错位","：界面越过控制器直接拿数据。改法是中间补一个 ",[200,888,710],{},"（§4.3）。",[22,891,892],{"id":892},"术语表",[56,894,895,908],{},[59,896,897],{},[62,898,899,902,905],{},[65,900,901],{},"术语",[65,903,904],{},"中文",[65,906,907],{},"一句话解释",[72,909,910,920,931,942,953,964,975,986,997,1008,1018,1028,1039,1048,1057,1067,1078,1089,1099,1110],{},[62,911,912,914,917],{},[77,913,636],{},[77,915,916],{},"统一建模语言",[77,918,919],{},"一套约定的建模符号",[62,921,922,925,928],{},[77,923,924],{},"class diagram",[77,926,927],{},"类图",[77,929,930],{},"描述类、属性、操作与关系的静态结构图",[62,932,933,936,939],{},[77,934,935],{},"object diagram",[77,937,938],{},"对象图",[77,940,941],{},"描述某一时刻具体对象及其引用关系",[62,943,944,947,950],{},[77,945,946],{},"sequence diagram",[77,948,949],{},"顺序图",[77,951,952],{},"用消息往来描述交互，纵向表示时间",[62,954,955,958,961],{},[77,956,957],{},"use case diagram",[77,959,960],{},"用例图",[77,962,963],{},"描述参与者、用例与系统边界",[62,965,966,969,972],{},[77,967,968],{},"class symbol",[77,970,971],{},"类符号",[77,973,974],{},"类图里表示一个类的矩形，通常分三格",[62,976,977,980,983],{},[77,978,979],{},"attribute list",[77,981,982],{},"属性列表",[77,984,985],{},"类符号中间那一格，列出对象的状态",[62,987,988,991,994],{},[77,989,990],{},"operation",[77,992,993],{},"操作",[77,995,996],{},"类符号下面那一格，列出对象的行为",[62,998,999,1002,1005],{},[77,1000,1001],{},"visibility",[77,1003,1004],{},"可见性",[77,1006,1007],{},"用 +、-、# 表示成员的开放程度",[62,1009,1010,1012,1015],{},[77,1011,308],{},[77,1013,1014],{},"依赖",[77,1016,1017],{},"临时使用另一个对象的关系",[62,1019,1020,1022,1025],{},[77,1021,319],{},[77,1023,1024],{},"关联",[77,1026,1027],{},"长期持有对方引用的关系",[62,1029,1030,1033,1036],{},[77,1031,1032],{},"multiplicity",[77,1034,1035],{},"重数",[77,1037,1038],{},"一端可以对应多少个实例",[62,1040,1041,1043,1045],{},[77,1042,330],{},[77,1044,827],{},[77,1046,1047],{},"部分可独立存在的整体—部分关系",[62,1049,1050,1052,1054],{},[77,1051,345],{},[77,1053,831],{},[77,1055,1056],{},"部分随整体消亡的强聚合",[62,1058,1059,1061,1064],{},[77,1060,358],{},[77,1062,1063],{},"继承",[77,1065,1066],{},"子类复用并覆盖父类定义的关系",[62,1068,1069,1072,1075],{},[77,1070,1071],{},"lifeline",[77,1073,1074],{},"生命线",[77,1076,1077],{},"顺序图里表示一个参与对象的竖线",[62,1079,1080,1083,1086],{},[77,1081,1082],{},"message",[77,1084,1085],{},"消息",[77,1087,1088],{},"对象之间的一次调用",[62,1090,1091,1093,1096],{},[77,1092,664],{},[77,1094,1095],{},"激活条",[77,1097,1098],{},"表示对象正在处理的时间段",[62,1100,1101,1104,1107],{},[77,1102,1103],{},"endArrow \u002F endFill",[77,1105,1106],{},"端点样式 \u002F 是否填充",[77,1108,1109],{},"draw.io 里画菱形与三角的两个关键属性",[62,1111,1112,1115,1118],{},[77,1113,1114],{},"modeling tool",[77,1116,1117],{},"建模工具",[77,1119,1120],{},"用来绘制 UML 图的软件",{"title":234,"searchDepth":1122,"depth":1122,"links":1123},3,[1124,1126,1131,1135,1140,1145,1146,1147,1150],{"id":24,"depth":1125,"text":25},2,{"id":45,"depth":1125,"text":46,"children":1127},[1128,1129,1130],{"id":50,"depth":1122,"text":51},{"id":125,"depth":1122,"text":126},{"id":136,"depth":1122,"text":137},{"id":150,"depth":1125,"text":151,"children":1132},[1133,1134],{"id":154,"depth":1122,"text":155},{"id":190,"depth":1122,"text":191},{"id":281,"depth":1125,"text":282,"children":1136},[1137,1138,1139],{"id":285,"depth":1122,"text":286},{"id":450,"depth":1122,"text":451},{"id":573,"depth":1122,"text":574},{"id":589,"depth":1125,"text":590,"children":1141},[1142,1143,1144],{"id":593,"depth":1122,"text":594},{"id":668,"depth":1122,"text":669},{"id":688,"depth":1122,"text":689},{"id":713,"depth":1125,"text":714},{"id":743,"depth":1125,"text":744},{"id":777,"depth":1125,"text":777,"children":1148},[1149],{"id":811,"depth":1122,"text":811},{"id":892,"depth":1125,"text":892},"学习",null,"2026-11-12","为什么需要一种共同的画法：类符号三格怎么画、五种关系的符号与设计含义、每种关系落到 Java 是什么写法，顺序图的三要素怎么摆；以及这三种最容易找不到的符号在 draw.io 里各搜什么词。","md",false,{},true,"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-21",{"title":5,"description":1154},"软件分析与设计笔记",21,"posts\u002FswDesign\u002Fsw-design-notes-21",[636,1165,1166,1167,1168],"软件设计","面向对象","绘图","学习笔记","Sw9vnNvjVvcnMzWRgYnlWKseCTxNId64ZD2kGMf1c8w",[1171,1177,1183,1189,1195,1201,1207,1213,1214,1220,1226,1232,1238,1244,1250,1256,1262,1268,1274,1280,1286,1292,1298,1304,1310,1316,1321,1326,1332,1338,1342,1346,1350,1354,1358,1362,1366,1370,1374,1378,1382,1388,1392,1398,1402,1406,1410,1414,1418,1422,1426,1431,1435,1439,1444,1449,1455,1459,1464,1468],{"path":1172,"title":1173,"description":1174,"date":1175,"series":1161,"seriesOrder":1176},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-28","软件分析与设计笔记 28：draw.io 作图手册：五张图的符号位置、落笔顺序与自检","不模拟软件界面，只讲清三件事：每个 UML 符号在 draw.io 里搜什么词、一张图该按什么顺序落笔、画完拿什么标准自查。覆盖用例图、活动图、顺序图、类图、界面草图五种图纸，末尾附「最容易画反的十二笔」总检表。","2026-11-19",28,{"path":1178,"title":1179,"description":1180,"date":1181,"series":1161,"seriesOrder":1182},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-27","软件分析与设计笔记 27：Paper 1 应试：从读案例到交卷的一次完整演算","拿一份完整的案例，从头到尾走一遍：怎么读案例列角色、怎么在四个小问之间分配时间、每一张图从哪一句话推出来、两张表怎么填、交卷前拿什么清单自查。附 C25 真题与样卷的题型分值对照。","2026-11-18",27,{"path":1184,"title":1185,"description":1186,"date":1187,"series":1161,"seriesOrder":1188},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-26","软件分析与设计笔记 26：总结：把整条链路串起来","系列收尾：从需求到代码的完整链路回顾、每一环的产出与验收方式、六条贯穿全系列的原则，以及一份可以直接拿去做项目自查的清单。","2026-11-17",26,{"path":1190,"title":1191,"description":1192,"date":1193,"series":1161,"seriesOrder":1194},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-25","软件分析与设计笔记 25：代码重构：坏味道与手法","重构不改变外部行为、只改善内部结构：四种常见坏味道与对应手法、为什么动手之前必须先有测试、什么时候该重构，以及重构和前面那些设计模型是什么关系。","2026-11-16",25,{"path":1196,"title":1197,"description":1198,"date":1199,"series":1161,"seriesOrder":1200},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-24","软件分析与设计笔记 24：设计原则：内聚、耦合与多态","好设计怎么衡量：内聚与耦合分别在说什么、一次从「差设计」到「多态重设计」的完整对照、抽象类与接口的选择依据，以及复用为什么会从优势变成风险。","2026-11-15",24,{"path":1202,"title":1203,"description":1204,"date":1205,"series":1161,"seriesOrder":1206},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-23","软件分析与设计笔记 23：设计建模：从对象模型到能实现的方案","分析模型能用但还不能直接开工：对象模型怎么映射到关系模型、继承映射的三种方案怎么选、数据访问层与 Data Broker 解决什么问题，以及三层架构与 MVC 的分工。","2026-11-14",23,{"path":1208,"title":1209,"description":1210,"date":1211,"series":1161,"seriesOrder":1212},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-22","软件分析与设计笔记 22：分析建模：边界、实体与控制对象","不经过分析直接写代码会踩什么坑、三种分析对象各管一段、怎么用顺序图完成一次用例实现，以及从顺序图导出类的属性、操作与关系的方法。","2026-11-13",22,{"path":1159,"title":5,"description":1154,"date":1153,"series":1161,"seriesOrder":1162},{"path":1215,"title":1216,"description":1217,"date":1218,"series":1161,"seriesOrder":1219},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-20","软件分析与设计笔记 20：面向对象概念：对象、关系与多态","面向对象不是「用某个语言写代码」：对象与类的区别、封装真正在保护什么、五种关系（依赖、关联、聚合、组合、继承）各自何时用，以及多态为什么能减少条件判断。","2026-11-11",20,{"path":1221,"title":1222,"description":1223,"date":1224,"series":1161,"seriesOrder":1225},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-19","软件分析与设计笔记 19：规范化与逻辑数据模型","一次改地址引发的数据不一致，讲清规范化的真正动机；UNF 到 3NF 每一步在解决什么问题，派生字段为什么不能存，优化为什么和规范化方向相反，以及逻辑数据模型在 3NF 之上补了什么。","2026-11-10",19,{"path":1227,"title":1228,"description":1229,"date":1230,"series":1161,"seriesOrder":1231},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-18","软件分析与设计笔记 18：数据库分析：实体、关系与数据字典","为什么不能拿到需求就动手建表：实体与关系怎么判定、基数为什么必须由业务方确认、数据命名要遵守什么规则，以及数据字典四列里最容易被空着的那一列。","2026-11-09",18,{"path":1233,"title":1234,"description":1235,"date":1236,"series":1161,"seriesOrder":1237},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-17","软件分析与设计笔记 17：用生成式 AI 做设计与开发：能用的场景与要防的坑","生成式 AI 在工作流里真正站得住的三个场景 —— 造示例数据、解释陌生代码、起草初稿；它为什么会复现社会偏见、为什么会编得像真的，以及哪些内容绝不能直接采用。","2026-11-08",17,{"path":1239,"title":1240,"description":1241,"date":1242,"series":1161,"seriesOrder":1243},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-16","软件分析与设计笔记 16：从 persona 到 URS：一份交付物的完整骨架","把前面十几篇串成一份能交出去的东西：用户需求规格说明书的九个部分、每一章来自哪个环节、由谁确认，以及面向决策者的提案该讲清哪三件事。","2026-11-07",16,{"path":1245,"title":1246,"description":1247,"date":1248,"series":1161,"seriesOrder":1249},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-15","软件分析与设计笔记 15：非功能需求：把「快、稳、安全」变成数字","为什么「系统要快」不是一条需求：非功能需求怎么量化，决定性能的用户量、交易量、数据量三张表怎么估，安全需求要写清什么，以及可靠性的「不可用」该怎么定义。","2026-11-06",15,{"path":1251,"title":1252,"description":1253,"date":1254,"series":1161,"seriesOrder":1255},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-14","软件分析与设计笔记 14：软件测试：层级、方法与等价类划分","「我们测过了」这句话问题在哪：为什么静态评审和动态测试缺一不可，五个测试层级各自验证什么，白盒与黑盒的差别，以及用等价类划分和边界值把无限输入变成有限用例的方法。","2026-11-05",14,{"path":1257,"title":1258,"description":1259,"date":1260,"series":1161,"seriesOrder":1261},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-13","软件分析与设计笔记 13：需求获取：五种调查方法与一场访谈","需求从哪里来：五种事实调查方法各自适合回答什么、代价是什么，访谈从准备到记录的全过程，问卷设计里最容易犯的错，以及访谈记录必须写下来的那几项信息。","2026-11-04",13,{"path":1263,"title":1264,"description":1265,"date":1266,"series":1161,"seriesOrder":1267},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-12","软件分析与设计笔记 12：前端设计：把流程变成屏幕","界面设计不是「画得好看」：从活动图走到屏幕的三步，CRUD 任务流怎么当检查表，界面必须回答的三个问题，信息架构与五种导航类型，视觉一致性与留白，以及移动端与 Web 端的差别。","2026-11-03",12,{"path":1269,"title":1270,"description":1271,"date":1272,"series":1161,"seriesOrder":1273},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-11","软件分析与设计笔记 11：Agentic AI 与业务流程自动化","AI agent 到底是什么：五项能力与四个核心组件，什么场景该用定时任务、什么该用程序、什么才值得用 agent，两种实现路径的差别，必须提前防住的四类失败模式，以及设计方法从提示词到编排的演进。","2026-11-02",11,{"path":1275,"title":1276,"description":1277,"date":1278,"series":1161,"seriesOrder":1279},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-10","软件分析与设计笔记 10：精炼用例模型：include、extend 与泛化","三种精炼用例关系的判断标准：include 什么时候用、它和 extend 的区别到底在哪、参与者泛化与用例泛化各解决什么问题，以及精炼到什么程度就该停手。","2026-11-01",10,{"path":1281,"title":1282,"description":1283,"date":1284,"series":1161,"seriesOrder":1285},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-09","软件分析与设计笔记 09：功能需求（二）：从流程到业务实体","活动图画完之后，怎么从流程里筛出真正的业务实体：三条判断标准、哪些名词其实不该建实体、属性从哪里来，以及领域模型和后面的数据模型分别负责什么。","2026-10-31",9,{"path":1287,"title":1288,"description":1289,"date":1290,"series":1161,"seriesOrder":1291},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-08","软件分析与设计笔记 08：功能需求（一）：用例模型与活动图","从用户故事到用例的翻译过程：什么才算「好」的参与者，系统边界怎么划，用例描述必须写清哪四件事，活动图怎么把分支、并行与泳道画清楚，以及这两个图在 draw.io 里各用哪个形状、最容易画错哪一笔。","2026-10-30",8,{"path":1293,"title":1294,"description":1295,"date":1296,"series":1161,"seriesOrder":1297},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-07","软件分析与设计笔记 07：用户故事：把需求写成可验收的一句话","用户故事的三段结构，怎么从用户画像和数据地图里把它提取出来，一条故事多大算合适、时序为什么也是需求的一部分，以及验收标准怎么写才算真的可验收。","2026-10-29",7,{"path":1299,"title":1300,"description":1301,"date":1302,"series":1161,"seriesOrder":1303},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-06","软件分析与设计笔记 06：范围界定（数据侧）：用数据校验你的判断","访谈结论和数字对不上时该怎么办：分析的四个层次分别在回答什么问题、为什么不能跳级、数据准备与搜集怎么做成一张应用地图，以及数据最容易在哪几个地方骗你。","2026-10-28",6,{"path":1305,"title":1306,"description":1307,"date":1308,"series":1161,"seriesOrder":1309},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-05","软件分析与设计笔记 05：范围界定（用户侧）：用户画像与客户旅程图","为什么「所有用户」是一个陷阱，项目边界该怎么划，用户画像要写哪五个要素、最容易写成什么废纸，客户旅程图怎么把阶段、想法和情绪画在同一张纸上，以及怎么从这两样东西一步步推到可验证的需求。","2026-10-27",5,{"path":1311,"title":1312,"description":1313,"date":1314,"series":1161,"seriesOrder":1315},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-04","软件分析与设计笔记 04：接手陌生案例的第一步：三问与一张表","拿到一个完全陌生的业务案例，怎么从零开始不跑偏：只问 Who、What、Why 三个问题，把「问题—事实—假设—理由」记成一张四列表，说清为什么假设必须写明理由，以及带着问题进访谈为什么比空手去有效得多。","2026-10-26",4,{"path":1317,"title":1318,"description":1319,"date":1320,"series":1161,"seriesOrder":1122},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-03","软件分析与设计笔记 03：Agile 与 Scrum：迭代、角色与产出物","从「三周做完交付，客户说这不是我要的」讲起，说清瀑布式与迭代式的根本差别，Scrum 的三个角色和三种产出物，一个 sprint 里四次固定活动各自在解决什么问题，以及敏捷里最常见的几个误解。","2026-10-25",{"path":1322,"title":1323,"description":1324,"date":1325,"series":1161,"seriesOrder":1125},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-02","软件分析与设计笔记 02：设计思维、用户驱动与数据驱动","从「客服要一个能一次看完所有排期的界面」这个翻车案例讲起，说清设计思维到底是什么、用户驱动与数据驱动各自能看见什么又看不见什么、为什么真正的落点是把两者合起来的 data-informed design，以及访谈中怎么问出有用的信息。","2026-10-24",{"path":1327,"title":1328,"description":1329,"date":1330,"series":1161,"seriesOrder":1331},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-01","软件分析与设计笔记 01：课程地图与从需求到设计的主干","这一篇不写具体方法，先把整条链路铺开：软件分析与设计到底要解决什么问题，从需求到设计分成哪两段，中间有哪十几个环节，一份完整的交付物里应该有什么，以及后面 27 篇笔记怎么排、新人该按什么顺序读。","2026-10-23",1,{"path":1333,"title":1334,"description":1335,"date":1336,"series":1337,"seriesOrder":1331},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-01","Spring 学习笔记 01：IoC、依赖注入与第一个 Spring Boot 应用","从「手写 new 出来的三层结构」的痛点讲起，说清 IoC 容器、Bean 与依赖注入是怎么回事，再用 Maven 与 Spring Initializr 跑起第一个能返回 JSON 的应用。","2026-10-15","Spring 学习笔记",{"path":1339,"title":1340,"description":1341,"date":1336,"series":1337,"seriesOrder":1125},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-02","Spring 学习笔记 02：Spring Data JPA 基础——实体映射与 Repository","用 ORM 把类映射到表：@Entity、@Id、@GeneratedValue 怎么用，CrudRepository 三层接口怎么选，H2 与 MySQL 怎么配，以及 ddl-auto 到底该写哪个值。",{"path":1343,"title":1344,"description":1345,"date":1336,"series":1337,"seriesOrder":1122},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-03","Spring 学习笔记 03：JPA 查询——派生方法、JPQL 与分页排序","Repository 自带的方法只够按主键查，这篇讲三种自己造查询的方式：方法名派生、@Query 写 JPQL、原生 SQL，以及 Pageable 分页排序和投影返回。",{"path":1347,"title":1348,"description":1349,"date":1336,"series":1337,"seriesOrder":1315},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-04","Spring 学习笔记 04：JPA 关联映射与仓储测试","一对多、多对多怎么映射，谁负责维护外键，FetchType 与 CascadeType 该怎么选，顺带用 @DataJpaTest 与 AssertJ 把仓储层测起来。",{"path":1351,"title":1352,"description":1353,"date":1336,"series":1337,"seriesOrder":1309},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-05","Spring 学习笔记 05：Spring MVC 与 Thymeleaf 入门","一次页面请求在 Spring MVC 里走了哪几步，@Controller 怎么把数据交给模板，@PathVariable 与 @RequestParam 怎么取参数，以及控制器为什么必须是无状态的。",{"path":1355,"title":1356,"description":1357,"date":1336,"series":1337,"seriesOrder":1303},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-06","Spring 学习笔记 06：表单绑定与服务端校验","把表单字段绑到对象上，用 Bean Validation 注解做服务端校验，把错误信息显示回用户刚填的那一页，再补上自定义校验注解与全局异常处理。",{"path":1359,"title":1360,"description":1361,"date":1336,"series":1337,"seriesOrder":1297},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-07","Spring 学习笔记 07：Thymeleaf 片段复用与国际化","用 th:fragment 与 th:insert\u002Fth:replace 把导航栏、页脚抽成片段，页面套用统一布局，再用 messages.properties 与 LocaleResolver 做中英文切换。",{"path":1363,"title":1364,"description":1365,"date":1336,"series":1337,"seriesOrder":1291},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-08","Spring 学习笔记 08：HTTP Session 与会话状态管理","HTTP 无状态带来的问题，Cookie 与 Session 怎么分工，Spring 里读写会话的几种方式，以及会话固定、超时、多实例共享这些必须想清楚的事。",{"path":1367,"title":1368,"description":1369,"date":1336,"series":1337,"seriesOrder":1285},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-09","Spring 学习笔记 09：拦截器 HandlerInterceptor","登录检查、权限判断、请求耗时统计这类横切逻辑该放哪：HandlerInterceptor 的三个回调各在什么时机执行，怎么注册与排除路径，以及它和过滤器的分工。",{"path":1371,"title":1372,"description":1373,"date":1336,"series":1337,"seriesOrder":1279},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-10","Spring 学习笔记 10：Service 层与事务","一组数据库操作要么全成功要么全失败，靠 @Transactional 怎么做到；传播行为、隔离级别、回滚规则怎么选，以及自调用失效、乐观锁悲观锁这些实战里的坑。",{"path":1375,"title":1376,"description":1377,"date":1336,"series":1337,"seriesOrder":1273},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-11","Spring 学习笔记 11：REST API 基础——把 Service 暴露成接口","同一套 Service 怎么同时服务页面和客户端：@RestController 的路由与方法语义、状态码怎么给、DTO 怎么定，以及 MockMvc 端到端和切片测试的两种写法与各自的坑。",{"path":1379,"title":1380,"description":1381,"date":1336,"series":1337,"seriesOrder":1267},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-12","Spring 学习笔记 12：REST 进阶——版本、更新、跨域与文档化","接口能跑通之后要处理的几件事：URL 与响应结构怎么定、版本怎么演进、更新怎么做到可安全重试、CORS 怎么配、HATEOAS 与 Spring Data REST 该不该用。",{"path":1383,"title":1384,"description":1385,"date":1386,"series":1387,"seriesOrder":1315},"\u002Fposts\u002Fjava\u002Fjava-functionalprogramming-notes","Java 函数式编程笔记：Lambda、函数式接口与 Streams","学习 Java 函数式编程时的个人笔记：Lambda 表达式的五步简写与方法引用、常见函数式接口、Stream 流水线与惰性求值，以及创建流、中间操作、终止操作与收集器的用法。示例代码均为自写，运行结果来自本地实测。","2026-10-13","Java 学习笔记",{"path":1389,"title":1390,"description":1391,"date":1386,"series":1387,"seriesOrder":1122},"\u002Fposts\u002Fjava\u002Fjava-generics-notes","Java 泛型笔记：泛型方法、有界类型与泛型类","学习 Java 泛型时的个人笔记：从重复的重载方法与多态尝试讲起，再到泛型方法与类型推断、有界泛型类型、Comparable 与 Number 边界，以及泛型类在集合中的用法。示例代码均为自写，运行结果来自本地实测。",{"path":1393,"title":1394,"description":1395,"date":1396,"series":1397,"seriesOrder":1315},"\u002Fposts\u002Fmysql\u002Fmysql-learning-04","MySQL 学习笔记 04：数据操纵（增删改）","MySQL 学习笔记第四篇：INSERT 插入（含批量插入与 INSERT ... SELECT）、UPDATE 更新、DELETE 删除，以及各自的坑。","2026-10-10","SQL 学习笔记",{"path":1399,"title":1400,"description":1401,"date":1396,"series":1397,"seriesOrder":1309},"\u002Fposts\u002Fmysql\u002Fmysql-learning-05","MySQL 学习笔记 05：DDL 概览","MySQL 学习笔记第五篇：数据定义语言概览——Schema、Table、View、Index、Constraints 这几类对象分别对应哪些 CREATE \u002F ALTER \u002F DROP 命令。",{"path":1403,"title":1404,"description":1405,"date":1396,"series":1397,"seriesOrder":1303},"\u002Fposts\u002Fmysql\u002Fmysql-learning-06","MySQL 学习笔记 06：CREATE TABLE 与数据类型","MySQL 学习笔记第六篇：CREATE TABLE 的完整语法、常用数据类型的选型建议，以及外键的两种定义方式。",{"path":1407,"title":1408,"description":1409,"date":1396,"series":1397,"seriesOrder":1297},"\u002Fposts\u002Fmysql\u002Fmysql-learning-07","MySQL 学习笔记 07：索引","MySQL 学习笔记第七篇：索引的作用与 B+ 树结构、单列与复合索引的创建、索引的代价与适用场景。",{"path":1411,"title":1412,"description":1413,"date":1396,"series":1397,"seriesOrder":1291},"\u002Fposts\u002Fmysql\u002Fmysql-learning-08","MySQL 学习笔记 08：DROP 与 ALTER","MySQL 学习笔记第八篇：DROP 删除数据库对象、ALTER 修改表结构，以及常见的坑。",{"path":1415,"title":1416,"description":1417,"date":1396,"series":1397,"seriesOrder":1285},"\u002Fposts\u002Fmysql\u002Fmysql-learning-09","MySQL 学习笔记 09：约束与数据完整性","MySQL 学习笔记第九篇：SQL 约束——NOT NULL、CHECK、PRIMARY KEY、FOREIGN KEY 等如何保证数据完整性，以及它们的对比。",{"path":1419,"title":1420,"description":1421,"date":1396,"series":1397,"seriesOrder":1279},"\u002Fposts\u002Fmysql\u002Fmysql-learning-10","MySQL 学习笔记 10：视图","MySQL 学习笔记第十篇：视图（Views）的定义与特性、和表的对比、创建与使用，以及可更新视图的限制。",{"path":1423,"title":1424,"description":1425,"date":1396,"series":1397,"seriesOrder":1273},"\u002Fposts\u002Fmysql\u002Fmysql-learning-11","MySQL 学习笔记 11：存储过程","MySQL 学习笔记第十一篇：存储过程（Stored Procedures）的概念、创建与调用、带参数的写法，以及优缺点。",{"path":1427,"title":1428,"description":1429,"date":1430,"series":1397,"seriesOrder":1331},"\u002Fposts\u002Fmysql\u002Fmysql-learning-01","MySQL 学习笔记 01：MySQL 基础知识","MySQL 学习笔记第一篇：MySQL Server 与 Workbench 的安装，数据库与 DBMS 的基本概念，关系模型、ACID 事务、常见数据类型，以及后续的学习路线。","2026-10-09",{"path":1432,"title":1433,"description":1434,"date":1430,"series":1397,"seriesOrder":1125},"\u002Fposts\u002Fmysql\u002Fmysql-learning-02","MySQL 学习笔记 02：SELECT 查询与过滤","MySQL 学习笔记第二篇：SELECT 的基本语法与逻辑执行顺序，WHERE 过滤（比较、LIKE、IN、BETWEEN、NULL）、各种 JOIN、UNION 与子查询。",{"path":1436,"title":1437,"description":1438,"date":1430,"series":1397,"seriesOrder":1122},"\u002Fposts\u002Fmysql\u002Fmysql-learning-03","MySQL 学习笔记 03：聚合、分组与输出控制","MySQL 学习笔记第三篇：COUNT\u002FSUM\u002FAVG 等聚合函数、GROUP BY 分组、HAVING 过滤、ORDER BY 与 LIMIT，以及一条 SELECT 的完整逻辑执行顺序。",{"path":1440,"title":1441,"description":1442,"date":1443,"series":1387,"seriesOrder":1125},"\u002Fposts\u002Fjava\u002Fjava-oop-notes","Java 面向对象笔记：类、继承、多态与异常","学习 Java 面向对象编程时的个人笔记：类与对象、封装与访问修饰符、继承与多态、集合、抽象类与接口、异常处理。示例代码均为自写，运行结果来自本地实测。","2026-10-06",{"path":1445,"title":1446,"description":1447,"date":1448,"series":1387,"seriesOrder":1331},"\u002Fposts\u002Fjava\u002Fjava-basics-notes","Java 基础语法笔记：从环境安装到方法与数组","学习 Java 基础语法时的个人笔记：JDK 安装、输入输出、变量与运算符、条件与循环、字符串、数组与方法。示例代码均为自写，运行结果来自本地实测。","2026-10-05",{"path":1450,"title":1451,"description":1452,"date":1453,"series":1454,"seriesOrder":1331},"\u002Fposts\u002Fgit\u002Fgit-install-and-basics","Git 安装与基本使用","从装好 Git 到跑通日常提交流程，把最常用的几条命令和它们背后的三个区域讲清楚。","2026-10-04","Git 入门",{"path":1456,"title":1457,"description":1458,"date":1453,"series":1454,"seriesOrder":1125},"\u002Fposts\u002Fgit\u002Flocal-remote-repository","本地远程仓库的部署","用自己的机器当 Git 服务器：建一个裸仓库、走 SSH 连上去，把本地提交推上去。",{"path":1460,"title":1461,"description":1462,"date":1453,"series":1463,"seriesOrder":1331},"\u002Fposts\u002Fguide\u002Fguide-file-layout","文件都放在哪","文章、图片、封面分别放在仓库的什么位置，哪些目录可以放手改、哪些碰了会出问题。","博客使用指南",{"path":1465,"title":1466,"description":1467,"date":1453,"series":1463,"seriesOrder":1125},"\u002Fposts\u002Fguide\u002Fguide-frontmatter","frontmatter 每个字段是什么意思","文章开头那段被横线包住的字段，逐个说明作用、默认行为和写错的后果。",{"path":1469,"title":1470,"description":1471,"date":1453,"series":1463,"seriesOrder":1122},"\u002Fposts\u002Fguide\u002Fguide-markdown","正文怎么写 —— Markdown 与排版效果","标题、链接、图片、代码、表格分别怎么写，以及本站对它们做了哪些自定义处理。",1793268185466]