\n \u003C/div>\n\u003C/template>\n\n\u003Cstyle lang=\"scss\" scoped>\n.quill-container {\n width: 100%;\n height: 100%;\n min-height: 200px;\n display: flex;\n flex-direction: column;\n line-height: normal;\n\n :deep(.ql-toolbar) {\n border-top-left-radius: 4px;\n border-top-right-radius: 4px;\n }\n\n :deep(.ql-container) {\n font-size: 16px;\n border-bottom-left-radius: 4px;\n border-bottom-right-radius: 4px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',\n 'Helvetica Neue', sans-serif;\n }\n\n :deep(.ql-blank::before) {\n font-style: normal;\n }\n\n :deep(.ql-undo[disabled]),\n :deep(.ql-redo[disabled]) {\n opacity: 0.5;\n cursor: not-allowed;\n\n .ql-stroke {\n stroke: #444 !important;\n }\n }\n\n :deep(.ql-mention-list) {\n padding: 4px;\n }\n\n :deep(.ql-mention-list-item) {\n padding: 0;\n line-height: normal;\n border-radius: 3px;\n }\n\n // mention style\n :deep(.mention-list-item) {\n display: flex;\n padding: 4px 8px;\n border-radius: 3px;\n align-items: center;\n\n .mention-avatar {\n width: 45px;\n height: 45px;\n border-radius: 50%;\n background-color: var(--el-text-color-disabled);\n color: var(--el-color-white);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--g-app-margin);\n overflow: hidden;\n flex-shrink: 0;\n }\n\n .mention-avatar-img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n .mention-text {\n flex: 1;\n display: flex;\n justify-content: flex-start;\n align-items: flex-start;\n flex-direction: column;\n }\n\n .mention-name {\n display: inline-block;\n font-size: 14px;\n font-weight: 400;\n line-height: 24px;\n text-transform: none;\n }\n .mention-email {\n color: var(--el-text-color-secondary);\n font-size: var(--el-font-size-extra-small);\n width: 160px;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n }\n}\n\u003C/style>\n```\n\n## 使用\n\n```vue\n\u003CQuillEditor ref=\"editorRef\" v-model:model-value=\"content\" :options=\"options\" />\n```\n",{"id":6,"createdAt":7,"updatedAt":7,"username":4,"from":8,"uniqueId":9,"status":10,"profile":150},{"id":6,"createdAt":12,"updatedAt":13,"nickName":14,"gender":10,"email":15,"phone":16,"avatar":17,"signature":18,"address":19,"birthDate":20,"introduction":21},[152,153],{"id":6,"createdAt":72,"updatedAt":72,"creator":16,"updater":16,"name":73},{"id":75,"createdAt":76,"updatedAt":76,"creator":16,"updater":16,"name":77},303,"/posts/44",{"id":157,"createdAt":158,"updatedAt":158,"createdBy":6,"updatedBy":6,"creator":4,"updater":4,"title":159,"description":160,"cover":30,"content":161,"top":60,"order":16,"status":32,"type":33,"contentType":52,"originalUrl":30,"author":162,"tags":164,"likeCount":60,"viewCount":169,"slug":170},43,"2025-07-24T14:01:53.576Z","依赖注入、控制反转","面向对象编程,必须了解依赖注入、控制反转的思想","依赖注入(DI,Dependency Inject)与控制反转(IoC,Invertion of Contorl)在许多框架中都存在,如spring、.net、nest等。很多小伙伴都听说过,却不是很了解。\n\n## 解释\n控制反转(IoC),是一种设计原则(设计思想)。用于对象与对象之间的解耦。在传统编程中,对象通常会自行创建和管理其依赖对象,导致组件之间的耦合度高。实现依赖注入的方式就是通过控制反转,将创建对象和依赖关系过程交给外部容器。\n\n```javascript\nclass A\n{\n constructor(B){\n // 因为A掌控B的创建,因此A控制了B\n this.b = new B();\n }\n} \n```\n\n依赖注入(Dependency Inject,DI),也叫注入,是一种设计模式(具体实现)。将对象的创建和依赖关系管理由外部容器负责,而不是在具体使用到对象的地方管理。\n```javascript\nclass A\n{\n // B由外部注入,称之为依赖注入\n constructor(B)\n {\n // B由外部创建,脱离了A的控制,称之为控制反转\n this.b = B;\n }\n} \n```\n\n## 为什么需要依赖注入和控制反转\n\n### 解耦\n\n\n\n相信大家都听说过一个法则:“高内聚,低耦合”,第一张图,B 依赖了 A,而 C 通过依赖 B 依赖了 A,稍微多一点这种关系,就会很复杂,难以维护。如果 我们把 B 和 C 所依赖的功能向 A 内聚,那么 B 和 C 就实现了解耦。\n\n还有一种方式是做抽象的接口,只要遵循一定的规则,你就可以把具体的实现使用到这个接口上,这也是解耦。比如内存卡,使用内存卡的设备只是一个接口,而内存卡就是这个接口的具体实现,所以你就可以把不同的内存卡(遵循标准生产的)使用到这个设备上。\n\n\n## IoC 容器\n\n\n\n在项目里,通常会遇到两个关于对象的问题,一个是对象数量多,如何统一管理对象的创建和销毁,依赖一个问题是对象间的依赖错综复杂,如何管理他们的依赖关系?\n\n针对上述问题,解决方案就是 IoC 容器,IoC 容器是一个对象管理器,它统一管理对象的创建过程、生命周期、依赖关系,以及提供自动注入,根据配置创建对象的功能。\n\n开源IoC容器Autofac:\n```c#\nusing Autofac;\n\nnamespace AutofacDemo\n{\n class A\n { }\n\n class B\n {\n A _a;\n // 只需要声明需要注入的对象,由容器自动完成依赖对象的创建与注入\n public B(A a)\n {\n _a = a;\n }\n }\n\n internal class Program\n {\n static void Main(string[] args)\n {\n // 将类型注册至容器中\n ContainerBuilder builder = new ContainerBuilder();\n builder.RegisterType\u003CA>();\n // 设置对象的生命周期(单例模式)\n builder.RegisterType\u003CB>().SingleInstance();\n\n // 构造IoC容器\n IContainer container = builder.Build();\n // 从容器中获取对象\n B b = container.Resolve\u003CB>();\n }\n }\n} \n```\n",{"id":6,"createdAt":7,"updatedAt":7,"username":4,"from":8,"uniqueId":9,"status":10,"profile":163},{"id":6,"createdAt":12,"updatedAt":13,"nickName":14,"gender":10,"email":15,"phone":16,"avatar":17,"signature":18,"address":19,"birthDate":20,"introduction":21},[165],{"id":166,"createdAt":167,"updatedAt":167,"creator":16,"updater":16,"name":168},13,"2025-07-22T13:50:49.520Z","软件设计原则",298,"/posts/43",{"id":172,"createdAt":173,"updatedAt":173,"createdBy":6,"updatedBy":6,"creator":4,"updater":4,"title":174,"description":175,"cover":30,"content":176,"top":60,"order":16,"status":32,"type":33,"contentType":52,"originalUrl":30,"author":177,"tags":179,"likeCount":60,"viewCount":181,"slug":182},42,"2025-07-22T13:50:49.527Z","SOLID (面向对象设计)","我们编写的代码是否符合规范,不仅需要从项目自身的代码规范上来看,也要从是否符合软件设计原则上来看,这也是为什么很多时候功能实现了,code review 不通过的原因,学好基本的软件设计原则,有助于我们写出健壮的代码。","# SOLID 面向对象设计\nSOLID(单一功能、开闭原则、里氏替换、接口隔离、依赖反转)\n\n# S \n单一功能原则(Single responsibility principle),规定每个类都应该有一个单一的功能,并且该功能由这个类完全封装起来,不能和其他平行的类有依赖。\n[参见 维基百科 - 单一功能原则](https://zh.wikipedia.org/wiki/%E5%8D%95%E4%B8%80%E5%8A%9F%E8%83%BD%E5%8E%9F%E5%88%99)\n\n# O\n开闭原则(The Open/Closed principle, OCP),软件中的对象(类、模块、函数等),对于扩展是开放的,对于修改是封闭的。\n[参见 维基百科 - 开闭原则](https://zh.wikipedia.org/wiki/%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99)\n\n# L\n里氏替换原则(Liskov substitution principle),派生类(子类)对象可以在程序中代替其基类(超类)对象。\n[参见 维基百科 - 里氏替换原则](https://zh.wikipedia.org/wiki/%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99)\n\n# I\n接口隔离原则(interface-segregation principles, ISP),\n指明客户(client)不应被迫使用对其而言无用的方法或功能。[1]接口隔离原则(ISP)拆分非常庞大臃肿的接口成为更小的和更具体的接口,这样客户将会只需要知道他们感兴趣的方法。这种缩小的接口也被称为角色接口(role interfaces)。[2]接口隔离原则(ISP)的目的是系统解开耦合,从而容易重构,更改和重新部署\n[参见 维基百科 - 接口隔离原则](https://zh.wikipedia.org/wiki/%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99)\n\n# D\n依赖反转原则(Dependency Inversion Principle,DIP),是指一种特定的解耦(传统的依赖关系建立在高层次上,而具体的策略设置则应用在低层次的模块上)形式,使得高层次的模块不依赖于低层次的模块的实现细节,依赖关系被颠倒(反转),从而使得低层次模块依赖于高层次模块的需求抽象。\n\n高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口。\n抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。",{"id":6,"createdAt":7,"updatedAt":7,"username":4,"from":8,"uniqueId":9,"status":10,"profile":178},{"id":6,"createdAt":12,"updatedAt":13,"nickName":14,"gender":10,"email":15,"phone":16,"avatar":17,"signature":18,"address":19,"birthDate":20,"introduction":21},[180],{"id":166,"createdAt":167,"updatedAt":167,"creator":16,"updater":16,"name":168},54,"/posts/42",19,["Reactive",185],{"$scolor-mode":186,"$ssite-config":190},{"preference":187,"value":187,"unknown":188,"forced":189},"system",true,false,{"_priority":191,"env":194,"name":195,"url":196},{"name":192,"env":193,"url":192},-3,-15,"production","小张的个人博客","https://blog.mrzym.top",["Set"],["ShallowReactive",199],{"home-posts":-1,"username":-1,"bloggerInfo":-1},"/",{"user":202,"blogArticle":204},{"user":16,"mentionList":203},[],{"currentArticle":16,"refresh":189}]