<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Archetect on DoDoRo的梦想空间-码农,数学,算法,哲学,园艺</title>
    <link>https://dodoro.chouxiangpai.com/categories/archetect/</link>
    <description>Recent content in Archetect on DoDoRo的梦想空间-码农,数学,算法,哲学,园艺</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Thu, 14 Mar 2024 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://dodoro.chouxiangpai.com/categories/archetect/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>《架构整洁之道》：Chap11. DIP: THE DEPENDENCY INVERSION PRINCIPLE DIP：依赖反转原则</title>
      <link>https://dodoro.chouxiangpai.com/archives/2065/</link>
      <pubDate>Thu, 14 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/2065/</guid>
      <description>&lt;p&gt;The Dependency Inversion Principle (DIP) tells us that the most flexible systems are those in which source code dependencies refer only to abstractions, not to concretions.&lt;/p&gt;
&lt;p&gt;依赖反转原则（DIP）主要想告诉我们的是，如果想要设计一个灵活的系统，在源代码层次的依赖关系中就应该多引用抽象类型，而用具体实现。&lt;/p&gt;
&lt;p&gt;In a statically typed language, like Java, this means that the use, import, and include statements should refer only to source modules containing interfaces, abstract classes, or some other kind of abstract declaration. Nothing concrete should be depended on.&lt;/p&gt;
&lt;p&gt;也就是说，在 Java 这类静态类型的编程语言中，在使用 use、import、include 这些语句时应该只引用那些包含接口、抽象类或者其他抽象类型声明的源文件，不应该引用任何具体实现。&lt;/p&gt;</description>
    </item>
    <item>
      <title>《架构整洁之道》：Chap10. ISP: THE INTERFACE SEGREGATION PRINCIPLE ISP：接口隔离原则</title>
      <link>https://dodoro.chouxiangpai.com/archives/2063/</link>
      <pubDate>Wed, 13 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/2063/</guid>
      <description>&lt;p&gt;The Interface Segregation Principle (ISP) derives its name from the diagram shown in Figure 10.1.&lt;/p&gt;
&lt;p&gt;“接口隔离原则（ISP）”这个名字来自图 10.1 所示的这种软件结构。&lt;/p&gt;
&lt;p&gt;The Interface Segregation Principle&lt;/p&gt;
&lt;p&gt;In the situation illustrated in Figure 10.1, there are several users who use the operations of the OPS class. Let’s assume that User1 uses only op1, User2 uses only op2, and User3 uses only op3.&lt;/p&gt;
&lt;p&gt;在图 10.1 所描绘的应用中，有多个用户需要操作 OPS 类。现在，我们假设这里的 User1 只需要使用 op1，User2 只需要使用 op2，User3 只需要使用 op3。&lt;/p&gt;
&lt;p&gt;Now imagine that OPS is a class written in a language like Java. Clearly, in that case, the source code of User1 will inadvertently depend on op2 and op3, even though it doesn’t call them. This dependence means that a change to the source code of op2 in OPS will force User1 to be recompiled and redeployed, even though nothing that it cared about has actually changed.&lt;/p&gt;</description>
    </item>
    <item>
      <title>《架构整洁之道》：Chap9. LSP: THE LISKOV SUBSTITUTION PRINCIPLE LSP：里氏替换原则</title>
      <link>https://dodoro.chouxiangpai.com/archives/2061/</link>
      <pubDate>Tue, 12 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/2061/</guid>
      <description>&lt;p&gt;In 1988, Barbara Liskov wrote the following as a way of defining subtypes.&lt;/p&gt;
&lt;p&gt;1988 年，Barbara Liskov 在描述如何定义子类型时写下了这样一段话：&lt;/p&gt;
&lt;p&gt;What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.1&lt;/p&gt;</description>
    </item>
    <item>
      <title>《架构整洁之道》：Chap8. OCP: THE OPEN-CLOSED PRINCIPLE OCP：开闭原则</title>
      <link>https://dodoro.chouxiangpai.com/archives/2059/</link>
      <pubDate>Mon, 11 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/2059/</guid>
      <description>&lt;p&gt;The Open-Closed Principle (OCP) was coined in 1988 by Bertrand Meyer.1 It says:&lt;/p&gt;
&lt;p&gt;开闭原则（OCP）是 Bertrand Meyer 在 1988 年提出的，该设计原则认为：&lt;/p&gt;
&lt;p&gt;A software artifact should be open for extension but closed for modification.&lt;/p&gt;
&lt;p&gt;设计良好的计算机软件应该易于扩展，同时抗拒修改。&lt;/p&gt;
&lt;p&gt;In other words, the behavior of a software artifact ought to be extendible, without having to modify that artifact.&lt;/p&gt;
&lt;p&gt;换句话说，一个设计良好的计算机系统应该在不需要修改的前提下就可以轻易被扩展。&lt;/p&gt;
&lt;p&gt;This, of course, is the most fundamental reason that we study software architecture. Clearly, if simple extensions to the requirements force massive changes to the software, then the architects of that software system have engaged in a spectacular failure.&lt;/p&gt;</description>
    </item>
    <item>
      <title>《架构整洁之道》：Chap7. SRP: THE SINGLE RESPONSIBILITY PRINCIPLE SRP：单一职责原则</title>
      <link>https://dodoro.chouxiangpai.com/archives/2057/</link>
      <pubDate>Sun, 10 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/2057/</guid>
      <description>&lt;p&gt;Of all the SOLID principles, the Single Responsibility Principle (SRP) might be the least well understood. That’s likely because it has a particularly inappropriate name. It is too easy for programmers to hear the name and then assume that it means that every module should do just one thing.&lt;/p&gt;
&lt;p&gt;SRP 是 SOLID 五大设计原则中最容易被误解的一个。也许是名字的原因，很多程序员根据 SRP 这个名字想当然地认为这个原则就是指：每个模块都应该只做一件事。&lt;/p&gt;
&lt;p&gt;Make no mistake, there is a principle like that. A function should do one, and only one, thing. We use that principle when we are refactoring large functions into smaller functions; we use it at the lowest levels. But it is not one of the SOLID principles—it is not the SRP.&lt;/p&gt;</description>
    </item>
    <item>
      <title>《架构整洁之道》：Part3. DESIGN PRINCIPLES 设计原则</title>
      <link>https://dodoro.chouxiangpai.com/archives/2054/</link>
      <pubDate>Sat, 09 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/2054/</guid>
      <description>&lt;p&gt;Good software systems begin with clean code. On the one hand, if the bricks aren’t well made, the architecture of the building doesn’t matter much. On the other hand, you can make a substantial mess with well-made bricks. This is where the SOLID principles come in.&lt;/p&gt;
&lt;p&gt;通常来说，要想构建一个好的软件系统，应该从写整洁的代码开始做起。毕竟，如果建筑所使用的砖头质量不佳，那么架构所能起到的作用也会很有限。反之亦然，如果建筑的架构设计不佳，那么其所用的砖头质量再好也没有用。这就是 SOLID 设计原则所要解决的问题。&lt;/p&gt;
&lt;p&gt;The SOLID principles tell us how to arrange our functions and data structures into classes, and how those classes should be interconnected. The use of the word “class” does not imply that these principles are applicable only to object-oriented software. A class is simply a coupled grouping of functions and data. Every software system has such groupings, whether they are called classes or not. The SOLID principles apply to those groupings.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Importance of SOLID Design Principles</title>
      <link>https://dodoro.chouxiangpai.com/archives/1900/</link>
      <pubDate>Wed, 19 Apr 2023 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1900/</guid>
      <description>&lt;p&gt;Author: Stephen Watts&lt;/p&gt;
&lt;p&gt;SOLID is a popular set of design principles that are used in object-oriented software development. SOLID is an acronym that stands for five key design principles: &lt;strong&gt;single responsibility principle, open-closed principle, Liskov substitution principle, interface segregation principle, and dependency inversion principle.&lt;/strong&gt; All five are commonly used by software engineers and provide some important benefits for developers.&lt;/p&gt;
&lt;p&gt;The SOLID principles were developed by Robert C. Martin in a 2000 essay, “Design Principles and Design Patterns,” although the acronym was coined later by Michael Feathers. In his essay, Martin acknowledged that successful software will change and develop. As it changes, it becomes increasingly complex. Without good design principles, Martin warns that software becomes rigid, fragile, immobile, and viscous. &lt;strong&gt;The SOLID principles were developed to combat these problematic design patterns&lt;/strong&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>里氏替换原则Liskov substitation principle</title>
      <link>https://dodoro.chouxiangpai.com/archives/1902/</link>
      <pubDate>Wed, 19 Apr 2023 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1902/</guid>
      <description>&lt;h2 id=&#34;为什么叫里氏替换原则&#34;&gt;为什么叫里氏替换原则？&lt;/h2&gt;
&lt;p&gt;里氏替换原则在SOLID这五个设计原则中是比较特殊的存在：如果违反了里氏替换原则，不只是降低软件设计的优雅性，很可能会导致Bug。&lt;/p&gt;
&lt;p&gt;里氏替换原则译自Liskov substitution principle。Liskov是一位计算机科学家，也就是Barbara Liskov，麻省理工学院教授，也是美国第一个计算机科学女博士，师从图灵奖得主John McCarthy教授，人工智能概念的提出者。&lt;/p&gt;
&lt;p&gt;Robert Martin在《敏捷软件开发：原则、模式与实践》一书中对原论文的解读：子类型（subtype）必须能够替换掉他们的基类型（base type）。这个是更简明的一种表述。&lt;/p&gt;
&lt;h2 id=&#34;违背-lsp-原则的一个简单示例&#34;&gt;违背 LSP 原则的一个简单示例&lt;/h2&gt;
&lt;p&gt;一个非常明显地违背 LSP原则的示例就是使用 RTTI（Run Time Type Identification）来根据对象类型选择函数执行。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; DrawShape(&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; Shape&amp;amp; s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (typeid(s) == typeid(Square))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DrawSquare(static_cast&amp;lt;Square&amp;amp;&amp;gt;(s));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (typeid(s) == typeid(Circle))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        DrawCircle(static_cast&amp;lt;Circle&amp;amp;&amp;gt;(s));
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;正方形和长方形违背原则的微妙之处&#34;&gt;正方形和长方形，违背原则的微妙之处&lt;/h2&gt;
&lt;p&gt;很多情况下对 LSP 原则的违背方式都十分微妙。设想在一个应用程序中使用了 Rectangle 类，描述如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Rectangle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; _width;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; _height;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; SetWidth(&lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; w) { _width = w; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; SetHeight(&lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; w) { _height = w; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; GetWidth() { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; _width; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; GetHeight() { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; _height; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;违反里氏替换原则的危害&#34;&gt;违反里氏替换原则的危害&lt;/h2&gt;
&lt;p&gt;当我们违反了这一原则会带来有一些危害：反直觉。期望所有子类行为是一致的，但如果不一致可能需要文档记录，或者在代码跑失败后涨此知识；不可读。如果子类行为不一致，可能需要不同的逻辑分支来适配不同的行为，徒增代码复杂度；不可用。可能出错的地方终将会出错。&lt;/p&gt;</description>
    </item>
    <item>
      <title>整理和总结我自己的软件架构知识体系</title>
      <link>https://dodoro.chouxiangpai.com/archives/1890/</link>
      <pubDate>Mon, 03 Apr 2023 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1890/</guid>
      <description>&lt;p&gt;最近开始整理自己实际项目中用到的和可能用到的软件架构体系，我打算每种架构都好好写文章，并且根据自己的实际情况定制出相应的架构，我还希望把他编写成一个codesmith模板，可以实现自动化代码。前面7种是具体落地的软件架构，最后1种是架构设计思想。&lt;/p&gt;
&lt;p&gt;1、极简数据库访问架构，这种架构非常适合编写一些小软件，里面只有一个SQLHelper文件，并且模仿三层架构，拥有DAL类和BLL类，最后加上一个程序入口Program。&lt;/p&gt;
&lt;p&gt;2、简单三层架构，这种架构非常适合开发小型项目，web层就是MVC或者API，并且拥有BLL层和DAL层。&lt;/p&gt;
&lt;p&gt;3、N层架构，这是一种适合大型项目的开发架构，但是更多是基于数据库构建的系统，没有基于DDD或者其他好的软件设计模式。&lt;/p&gt;
&lt;p&gt;4、基于AutoFac、依赖注入和模板模式的多层架构。&lt;/p&gt;
&lt;p&gt;5、基于ABP框架的架构，完全按照DDD设计模式开发，可能有些臃肿，但是非常适合大型软件和系统。&lt;/p&gt;
&lt;p&gt;6、基于整洁架构的框架，完全按照DDD并且结合各种软件技术。&lt;/p&gt;
&lt;p&gt;7、垂直切片架构，这是一种和传统分成架构完全不一样的架构，适合已经熟悉DDD和各种架构模式的成熟团队使用，并且适合开发微服务架构下的子系统。&lt;/p&gt;
&lt;p&gt;8、基于清晰架构的微服务软件架构设计思想，这不是具体的实现，而只是一种架构大局观，用于指导大型的软件架构设计。&lt;/p&gt;</description>
    </item>
    <item>
      <title>[转]垂直切片架构 - Jimmy Bogard</title>
      <link>https://dodoro.chouxiangpai.com/archives/1875/</link>
      <pubDate>Fri, 24 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1875/</guid>
      <description>&lt;p&gt;许多年前，我们开始了一个新的长期项目，首先，我们基于洋葱架构构建了它的架构。在几个月内，这种风格开始显示出裂缝，我们从这种架构转向CQRS。随着转向CQRS，我们开始围绕垂直切片而不是层（无论是平面还是同心，它仍然是层）构建我们的架构。从那以后，在过去7到8年左右的时间里，围绕垂直切片架构构建应用程序和系统的所有方式一直是我们独有的方法，我无法想象回到分层架构方法的限制。&lt;/p&gt;
&lt;p&gt;传统的分层/洋葱/清洁架构在其目标是单体的：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/cleanarchitecture.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1875/images/cleanarchitecture.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这种架构方式问题是实际上只适用于系统中的少数典型请求。此外，我倾向于看到这些架构严重拟合，严格遵守依赖关系管理规则。在实践中，我发现这些规则很少有用，并且你开始得到很多关于真正不应该被抽象的抽象（控制器必须与必须使用存储库的服务进行对话）。&lt;/p&gt;
&lt;p&gt;相反，我想对我的系统采用量身定制的方法，我将每个请求视为如何处理其代码的独特用例。因为我的系统整齐地分解为“命令”请求和“查询”请求（HTTP-land中的GET与POST / PUT / DELETE），所以向垂直切片架构的移动使我使用了CQRS。&lt;/p&gt;
&lt;p&gt;什么是“垂直切片架构”？在这种风格中，我的架构是围绕不同的具体请求功能而构建的，通过这种方法，我们的每个垂直切片都可以自行决定如何最好地满足请求：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/Picture0031.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1875/images/Picture0031.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;(对于获取订单，直接使用ORM转换为DTO，对于订单细节使用原生SQL转换为DTO，对于发票，使用基于聚合根的事件溯源，取消订单使用存储过程，这是一种微服务风格)&lt;/p&gt;
&lt;p&gt;在所谓正常的“n层”或六边形或任何架构中，通过垂直切片移除这些层障碍，并沿着变化轴聚合在一起：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/Picture0030.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1875/images/Picture0030.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在应用程序中添加或更改功能时，通常会在应用程序中涉及到许多不同的“层”。现在改为沿着切片垂直将这些功能聚合在一起。&lt;/p&gt;
&lt;p&gt;最小化切片之间的耦合，并最大化切片内的聚合。&lt;/p&gt;
&lt;p&gt;通过这种方法，大多数抽象都消失了，我们不需要任何类型的“共享”层抽象，如存储库，服务，控制器。有时我们仍需要这些工具，但我们将交叉切片逻辑共享保持在最低限度。&lt;/p&gt;
&lt;p&gt;通过这种方法，我们的每个垂直切片都可以自行决定如何最好地满足请求。&lt;/p&gt;
&lt;p&gt;“企业架构模式”一书中的旧域逻辑模式不再需要成为应用程序范围内的选择。相反，我们可以从简单的（事务脚本）开始，并简单地重构从我们在业务逻辑中看到的代码气味中出现的模式。新功能只添加代码，您不会更改共享代码并担心副作用。非常自由！&lt;/p&gt;
&lt;p&gt;但是，这种方法有一些缺点，因为它确实假设您的团队了解代码气味和重构。如果您的团队不理解“服务”在将逻辑推送到领域时自己却做得太多相关业务逻辑事情，那么这种模式可能不适合您。（服务类似餐厅服务员，服务员不应该做决定，只是协调者，当然如果你想退菜，服务员会决定说：不能退，菜已经烧了。）&lt;/p&gt;
&lt;p&gt;如果您的团队确实理解了重构，并且能够识别何时将复杂的逻辑推入域，进入DDD服务应该是什么，并且熟悉其他Fowler/Kerievsky重构技术，那么您会发现这种架构风格能够远远超过传统的分层/同心架构。&lt;/p&gt;
&lt;p&gt;来源：&lt;a href=&#34;https://www.jdon.com/53095.html&#34;&gt;https://www.jdon.com/53095.html&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>关于软件的架构：微服务架构、清晰架构、整洁架构、洋葱架构、六边形架构、垂直切片架构、基于DDD分层架构、三层架构</title>
      <link>https://dodoro.chouxiangpai.com/archives/1864/</link>
      <pubDate>Fri, 24 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1864/</guid>
      <description>&lt;p&gt;这段时间一直在重构公司的项目代码，所以非常关注软件架构的设计，回顾我的架构接触史：第一次接触C#和.NET的时候就知道了三层架构和多层架构，当时被DAL和BLL等分层震惊了，原来软件设计还有那么多门道；毕业之后工作一直在使用多层架构，接着是MVC架构的出现，这种快速开发web站点的架构横扫整个行业；后来进入大厂工作，接触到了DDD；最近几年微服务架构又风声水起。&lt;/p&gt;
&lt;p&gt;整体下来我最开始用了三层架构、然后是多层架构，接着是MVC架构配合多层架构，最后到了微服务架构，现在深刻理解那句话：没有最好的架构，只有最合适的架构。&lt;/p&gt;
&lt;p&gt;网上看到有个人总结传统的架构演变之路：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/584866-20221111185736123-254492615.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1864/images/584866-20221111185736123-254492615.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三层架构&lt;/strong&gt;：这是最简单、同时也是最成熟的软件应用程序架构，它将应用程序组织到三个逻辑和物理计算层中，包括表示层或用户界面、用于处理数据的应用(业务逻辑)程序层和用于存储和管理应用程序关联数据的数据层。大型项目中很少用，但是我还是会在一些小工具和小应用里运用。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;多层架构&lt;/strong&gt;：这种架构是三层架构的升级版，就是增加更多层对系统进行隔离，提高可扩展性和复用性，当然也增加了系统的复杂度。这是我刚毕业那家年用得最多的架构。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;基于DDD的分层架构&lt;/strong&gt;：采用领域驱动设计的思想设计的多层架构，以领域模型为核心、使用依赖注入和控制反转等技术来实现软件，对系统进行解耦，获得最大限度地可维护性和可扩展性。这是我现在在项目中用得最多的架构。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/584866-20221109112414965-235625557-1.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1864/images/584866-20221109112414965-235625557-1.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;领域模型准确反映了业务语言，而传统数据对象除了简单setter/getter方法外，没有任何业务方法，即失血模型，那么DDD领域模型就是充血模型（业务方法定义在实体对象中）。首次清晰描述了领域驱动的分层实现并统一了业务语言。单一职责、低耦合、高内聚、业务内核沉淀。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;六边形架构&lt;/strong&gt;：让用户、程序、自动化测试和批处理脚本可以平等地驱动应用，让应用的开发和测试可以独立于其最终运行的设备和数据库。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/584866-20221107162312997-555411461.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1864/images/584866-20221107162312997-555411461.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;左侧: 代表 UI 的适配器被称为主适配器，它们发起了对应用的一些操作，端口（应用层API）和它的具体实现(controller实现)都在应用内部。右侧: 表示和后端工具链接的适配器，被称为从适配器，它们只会对主适配器的操作作出响应，端口在应用内部(业务接口)，具体实现（impl）在应用之外。&lt;/p&gt;
&lt;p&gt;**洋葱架构：**在端口和适配器架构的基础上贯彻了将领域放在应用中心，将传达机制(UI)和系统使用的基础设施(ORM、搜索引擎、第三方 API&amp;hellip;)放在外围的思路。洋葱架构在业务逻辑中加入了一些在“领域驱动设计”中被识别出来的层次。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/584866-20221107202003888-2066385310.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1864/images/584866-20221107202003888-2066385310.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;围绕独立的对象模型构建应用。内层定义接口，外层实现接口。依赖的方向指向圆心。所有的应用代码可以独立于基础设施编译和运行。职责分离更彻底，高内聚低耦合。更好的可测试性和可维护性。&lt;/p&gt;
&lt;p&gt;**整洁架构：**这套架构是站在巨人的肩膀上，把MVC、EBI、端口适配器、洋葱架构、DDD融会贯通，形成了一套落地实践方案。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/584866-20221108113426021-86566397.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1864/images/584866-20221108113426021-86566397.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;清晰架构&lt;/strong&gt;：融合 DDD、洋葱架构、整洁架构、CQRS等一系列架构的信息，这种架构很复杂，你可以根据实际情况来选择。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230324160106.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1864/images/%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20230324160106.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;微服务架构&lt;/strong&gt;：微服务架构的诞生是因为docker的兴起，因为可以更好地管理各种部署，所以可以将一个大型系统拆分部署到docker之中，每个小服务都能实现集群部署。我个人认为并非一开始就要上微服务架构，架构是不断演化的过程，哪怕是一开始就定位很大系统，可以先划分出基本的服务就行（比如登录系统、支付中心、内容服务、接口开放平台和后台系统），更细的划分可以随着业务的发展不断演化——当然前提是要一直保证代码的整洁和简洁、遵循基本的面向对象代码原则。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;垂直切片架构&lt;/strong&gt;：我是最近才接触到了这种架构，我们的项目最近用到了MediatR和AutoMapper，这两个开源项目的作者Bogard JIMMY BOGARD在自己的项目中实现了这种架构，通过反思洋葱架构和整洁架构等各种分层和抽象得出来的一种架构，作者不建议做太多的分层，因为各种以来会导致大量的问题，作者认为在微服务架构里面特别实用，当然代码也会准从DDD的设计原则。作者认为在所谓传统正常的“N层”或六边形或任何架构中，通过垂直切片移除这些层障碍，并沿着变化轴聚合在一起：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/Picture0030.png&#34;&gt;&lt;img loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1864/images/Picture0030.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>解决Xcode 10 、Xcode11、Xcode12升级之后 &#39;string&#39; file not found C&#43;&#43;头文件、`libstdc&#43;&#43;6.0.9.tbd`库缺失问题</title>
      <link>https://dodoro.chouxiangpai.com/archives/1672/</link>
      <pubDate>Sat, 02 Apr 2022 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1672/</guid>
      <description>&lt;p&gt;最近公司的移动开发工程师被困在老家，项目有紧急需要修改的地方，我只好亲自上阵，打开Xcode改bug。编译的过程发现小伙子前阵子刚刚升级了，遇到了c++头文件无法编译的问题。网上查了一下，发现这是Xcode的通病，三个版本都有类似的问题。&lt;/p&gt;
&lt;p&gt;Xcode10 &amp;lsquo;string&amp;rsquo; file not found C++头文件缺失问题&lt;/p&gt;
&lt;p&gt;将对应文件拷贝到Xcode10对应目录下&lt;/p&gt;
&lt;p&gt;真机： /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/c++ 模拟器： /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/c++&lt;/p&gt;
&lt;p&gt;Xcode9 C++头文件github链接：&lt;a href=&#34;https://github.com/DeCori/Xcode9-cpp.git&#34;&gt;https://github.com/DeCori/Xcode9-cpp.git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Xcode10中缺少的libstdc++6.0.9.tbd库 其中文件夹 1、2、3、4 中的文件分别对应复制到Xcode10中的以下4个目录中即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/lib/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Xcode11和12文件的1路径发生改变：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>使用python的opencv库来移除黑色背景图</title>
      <link>https://dodoro.chouxiangpai.com/archives/1539/</link>
      <pubDate>Fri, 22 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1539/</guid>
      <description>&lt;p&gt;前两天为了研究隐形数字水印技术，了解了一些OpenCV的用法，涉及到把黑色背景图去掉的方法，别的不多说，直接上代码吧！&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; os
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; cv2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;path &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;D:/build/utensilspictureNew&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;#文件夹目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 遍历文件夹及其子文件夹中的文件，并存储在一个列表中&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 输入文件夹路径、空文件列表[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 返回 文件列表Filelist,包含文件名（完整路径）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get_filelist&lt;/span&gt;(dir):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    newDir &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; dir
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; os&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;isfile(dir):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        src  &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;imread(newDir,&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        tmp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;cvtColor(src, cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;COLOR_BGR2GRAY)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        _, alpha &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;threshold(tmp, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;, cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;THRESH_BINARY)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        b, g, r &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;split(src)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        rgba &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; [b, g, r, alpha]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        dst &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;merge(rgba, &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        cv2&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;imwrite(newDir, dst)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        print(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;Done&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;elif&lt;/span&gt; os&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;isdir(dir):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; s &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; os&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;listdir(dir):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            newDir&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;os&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;path&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;join(dir,s)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            get_filelist(newDir)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;get_filelist(path)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码还包括了如何递归遍历文件夹里的文件夹和文件。&lt;/p&gt;</description>
    </item>
    <item>
      <title>隐形数字水印技术</title>
      <link>https://dodoro.chouxiangpai.com/archives/1537/</link>
      <pubDate>Mon, 18 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1537/</guid>
      <description>&lt;p&gt;这两天需要给项目中的图片加水印，考虑到美观就放弃了显性的水印，而采用隐形的数字水印。利用数字水印的不可见性，在不影响作品的情况下，加入版权信息的数字水印，可抗击拷贝，剪切。&lt;/p&gt;
&lt;p&gt;数字水印（DigitalWatermarking）技术是将一些标识信息（即数字水印）直接嵌入数字载体（包括多媒体、文档、软件等）当中，但不影响原载体的使用价值，也不容易被人的知觉系统（如视觉或听觉系统）觉察或注意到，只有通过专用的检测器或阅读器才能提取。数字水印是一个崭新的信息隐藏技术，首次提出这个概念至今也不到20年。&lt;/p&gt;
&lt;p&gt;我采用的是github上面的一个开源库blind_watermark (&lt;a href=&#34;https://github.com/guofei9987/blind_watermark&#34;&gt;https://github.com/guofei9987/blind_watermark&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;这是基于小波变换的数字盲水印，用python来写的，效果还可以，不过通过通信软件截图或者发送之后，就无法获取到数字水印了，这个只能防那些直接拿来使用的盗用者。&lt;/p&gt;
&lt;p&gt;另外，如果图片上透明背景的png格式，转换之后会生成黑色底色，这个也很不好，我花了两天时间试图修改源码，还是没有完成。&lt;/p&gt;
&lt;p&gt;虽然没有能，但是学会了一些OpenCV的技术。&lt;/p&gt;</description>
    </item>
    <item>
      <title>用python给图片添加半透明水印</title>
      <link>https://dodoro.chouxiangpai.com/archives/1541/</link>
      <pubDate>Fri, 15 Oct 2021 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1541/</guid>
      <description>&lt;p&gt;我一直都是用C#来完成水印的生产，最近捣腾python脚本，查了一下，可以很方便地用python给图片添加半透明水印。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# coding:utf-8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;from&lt;/span&gt; PIL &lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; Image, ImageDraw, ImageFont
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;add_text_to_image&lt;/span&gt;(image, text):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    font &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ImageFont&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;truetype(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;C:\Windows\Fonts\STXINGKA.TTF&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;36&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;# 获取字体&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 添加背景&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    new_img &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;new(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RGBA&amp;#39;&lt;/span&gt;, (image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;), (&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    new_img&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;paste(image, image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 添加水印&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    font_len &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; len(text)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    rgba_image &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; new_img&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;convert(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RGBA&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    text_overlay &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;new(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;RGBA&amp;#39;&lt;/span&gt;, rgba_image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size, (&lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;255&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    image_draw &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ImageDraw&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;Draw(text_overlay)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, rgba_image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], font_len&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;40&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; j &lt;span style=&#34;color:#f92672&#34;&gt;in&lt;/span&gt; range(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, rgba_image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;], &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;):
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            image_draw&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;text((i, j), text, font&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;font, fill&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    text_overlay &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; text_overlay&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rotate(&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;45&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    image_with_text &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;alpha_composite(rgba_image, text_overlay)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 裁切图片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    image_with_text &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; image_with_text&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;crop((image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;], image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;], image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;size[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; image_with_text
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; __name__ &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    img &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Image&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;open(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;test.jpg&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    im_after &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; add_text_to_image(img, &lt;span style=&#34;color:#e6db74&#34;&gt;u&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;test_output&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    im_after&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;save(&lt;span style=&#34;color:#e6db74&#34;&gt;u&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;test_output.png&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>使用Github Action将.NET Core发布到docker Hub</title>
      <link>https://dodoro.chouxiangpai.com/archives/1137/</link>
      <pubDate>Mon, 15 Mar 2021 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/1137/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;去年公司已经完成所有产品的.NET Core改造工作，团队成员也逐步积累了docker和devops的知识，今年的主要任务之一就是把核心的产品迁移到devops生产线上。本来是打算用微软的Azure平台，因为真的太好用了，我自己的测试站点就一直用Azure来做持续交付工作。但是公司原来的产品、数据、备案都在阿里云上，迁移的话会有大量的工作，包括数据迁移、备案迁移都很麻烦。加上目前国内这种政治绝对正确的要求，搞不准哪天就因为用Azure就撞雷了，虽然很无语，但是也没有办法。&lt;/p&gt;
&lt;p&gt;这几天一直在想方案，前年是打算用开源的持续集成(CI)工具Jenkins来配合阿里云，不过去年发现GitHub Action用起来更加顺畅，而我们的代码基本都是托管在GitHub上面，阿里云去年也发布了自己的K8S平台ACK，我们打算当小白鼠，正式使用看看效果如何。&lt;/p&gt;
&lt;p&gt;不过在使用ACK之前，我们希望能够把Github上面的代码持续发布到docker Hub上面，去年已经完成了这部分工作，今天整理一下步骤和流程。&lt;/p&gt;
&lt;h2 id=&#34;一创建docker-hub账号&#34;&gt;一、创建docker Hub账号&lt;/h2&gt;
&lt;p&gt;首先是到 &lt;a href=&#34;https://hub.docker.com/&#34;&gt;https://hub.docker.com/&lt;/a&gt; 创建一个账号，并且创建一个自己的repository，可以是公开的，也可以是私有的。另外，设置和GitHub的连接： &lt;img alt=&#34;file&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1137/images/image-1617352132067.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;二创建dockerfile&#34;&gt;二、创建Dockerfile&lt;/h2&gt;
&lt;p&gt;通过VSCode或者VS创建自动Dockerfile，如果是VS，就右键项目(不是解决方案)，添加Docker支持，VS会自动生成这个项目的Dockerfile文件，不用做任何修改。 &lt;img alt=&#34;file&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1137/images/image-1617352255123.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;三提交整个解决方案&#34;&gt;三、提交整个解决方案&lt;/h2&gt;
&lt;p&gt;我们的项目一般都是位于一个解决方案里面，所以一个解决方案可能保护多个项目，这个没有问题，把整个解决方案都提交到GitHub上面，当然必须是本地可以编译通过并且可以运行的代码。网上很多教程都没有说清楚这种项目的打包细节，我后面会重点说一下，因为对于一个初学者，很容易在这里迷茫。&lt;/p&gt;
&lt;h2 id=&#34;四设置github的密钥&#34;&gt;四、设置GitHub的密钥&lt;/h2&gt;
&lt;p&gt;需要把第一步创建的Hub账号填写到GitHub的settings里面： &lt;img alt=&#34;file&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1137/images/image-1617353001890.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;五编写action的workflow&#34;&gt;五、编写Action的WorkFlow&lt;/h2&gt;
&lt;p&gt;通过Github的Action，可以创建很多类型的工作流WorkFlow，非常方便。 &lt;img alt=&#34;file&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1137/images/image-1617352492125.png&#34;&gt; 可以看到，几乎涵盖了所有国内外常用云平台的模板。 &lt;img alt=&#34;file&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1137/images/image-1617352575322.png&#34;&gt; 当然了，也包含了几乎所有常用开发语言的模板，太牛了。&lt;/p&gt;
&lt;p&gt;Github上还有非常多通用的Action，你可以直接引用来使用，这里我不多说，贴一个我们可以运行的WorkFlow：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;.NET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;push&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;branches&lt;/span&gt;: [ &lt;span style=&#34;color:#ae81ff&#34;&gt;master ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;pull_request&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;branches&lt;/span&gt;: [ &lt;span style=&#34;color:#ae81ff&#34;&gt;master ]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;docker&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;runs-on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;actions/checkout@v2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Setup .NET Core&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;actions/setup-dotnet@v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;dotnet-version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3.1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Push to Docker Hub&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;docker/build-push-action@v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;username&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${{ secrets.DOCKER_USERNAME }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${{ secrets.DOCKER_PASSWORD }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;dockerfile&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;./Academy.PCCore/Dockerfile&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;repository&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;academy/academypc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;tags&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;v0.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#f92672&#34;&gt;tag_with_ref&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里重点说一下后面的这几个变量： 1、username和password就是第四步里面设置的变量。 2、dockerfile的路径问题，路径“./”就是指当前在Github的这个respository的根目录，比如： &lt;img alt=&#34;file&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/1137/images/image-1617353172668.png&#34;&gt; 这里我只需要将Academy.PCCore项目打成docker，Dockerfile也在这个文件夹的根目录。 3、repository，这个就是在Docker Hub里面创建的仓储Respository的路径，两边一定要一直，否则无法提交。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【转】插画版Kubernetes指南</title>
      <link>https://dodoro.chouxiangpai.com/archives/966/</link>
      <pubDate>Tue, 02 Jun 2020 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/966/</guid>
      <description>&lt;p&gt;插画版Kubernetes指南（小孩子也能看懂的kubernetes教程） 是根据一个视频翻译过来的，比较形象&lt;/p&gt;
&lt;p&gt;编者按：Matt Butcher 是 Deis 的平台架构师，热爱哲学，咖啡和精雕细琢的代码。有一天女儿走进书房问他什么是 Kubernetes，于是就有了这本插画版的 Kubernetes 指南，讲述了勇敢的 Phippy（一个 PHP 应用），在 Kubernetes 的冒险故事，满满的父爱有木有！&lt;/p&gt;
&lt;p&gt;某一天&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/160704211922444.png&#34;&gt;&lt;img alt=&#34;160704211922444&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/966/images/160704211922444-300x200.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;有一天，女儿走进书房问我：『亲爱的爸爸，什么是 Kubernetes 呢？』&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/160704211922441.png&#34;&gt;&lt;img alt=&#34;160704211922441&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/966/images/160704211922441-300x200.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我回答她：『Kubernetes 是一个开源的 Docker 容器编排系统，它可以调度计算集群的节点，动态管理上面的作业，保证它们按用户期望的状态运行。通过使用「labels」和「pods」的概念，Kubernetes 将应用按逻辑单元进行分组，方便管理和服务发现。』&lt;/p&gt;
&lt;p&gt;女儿更疑惑了……于是就有了这个故事。&lt;/p&gt;
&lt;p&gt;给孩子的插画版 Kubernetes 指南&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/160704211922442.png&#34;&gt;&lt;img alt=&#34;160704211922442&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/966/images/160704211922442-300x200.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;很久很久以前，有一个叫 Phippy 的 PHP 应用，她很单纯，只有一个页面。她住在一个托管服务里，周围还有很多可怕的应用，她都不认识，也不想去认识，但是他们却要共享这里的环境。所以，她一直都希能有一个属于自己的环境：一个可以称作 home 的 webserver。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/160704211922446.png&#34;&gt;&lt;img alt=&#34;160704211922446&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/966/images/160704211922446-300x200.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;每个应用的运行都要依赖一个环境，对于一个 PHP 应用来说，这个环境包括了一个 webserver，一个可读的文件系统和 PHP 的 engine。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/160704211922443.png&#34;&gt;&lt;img alt=&#34;160704211922443&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/966/images/160704211922443-300x200.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;有一天，一只可爱的鲸鱼拜访了 Phippy，他建议 Phippy 住在容器里。Phippy 听从了鲸鱼的建议搬家了，虽然这个容器看起来很好，但是……怎么说呢，就像是漂浮在海上的一个小房间一样，还是没有家的感觉。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/160704211922445.png&#34;&gt;&lt;img alt=&#34;160704211922445&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/966/images/160704211922445-300x200.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;不过容器倒是为应用提供了隔离的环境，在这个环境里应用就能运行起来。但是这些相互隔离的容器需要管理，也需要跟外面的世界沟通。共享的文件系统，网络，调度，负载均衡和资源分配都是挑战。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/160704211922447.png&#34;&gt;&lt;img alt=&#34;160704211922447&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/966/images/160704211922447-300x200.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;『抱歉……孩子……』鲸鱼耸耸肩，一摇尾消失在了海平面下…… Phippy 还没有来得及失望，就看到远方驶来一艘巨轮，掌舵的老船长非常威风。这艘船乍一看就是大了点，等到船走近了，Phippy 才发现船体两边挂满了皮筏。&lt;/p&gt;
&lt;p&gt;老船长用充满智慧的语气对 Phippy 说：『你好，我是 Kube 船长』。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;images/160704211922449.png&#34;&gt;&lt;img alt=&#34;160704211922449&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/966/images/160704211922449-300x200.png&#34;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;『Kubernetes』是希腊语中的船长，后来的『Cybernetic』和『Gubernatorial』这两个词就是从 Kubernetes 衍生来的。Kubernetes 项目由 Google 发起，旨在为生产环境中成千上万的容器，构建一个健壮的平台。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【转】.NET Core微服务之ASP.NET Core on Docker</title>
      <link>https://dodoro.chouxiangpai.com/archives/956/</link>
      <pubDate>Mon, 01 Jun 2020 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/956/</guid>
      <description>&lt;p&gt;原作：Edison Zhou 恰童鞋骚年&lt;/p&gt;
&lt;h2 id=&#34;一docker极简介绍&#34;&gt;一、Docker极简介绍&lt;/h2&gt;
&lt;p&gt;1.1 总体介绍 &lt;img alt=&#34;file&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/956/images/image-1590996258971.png&#34;&gt; 　　Docker 是一个开源的应用容器引擎，基于 Go 语言 并遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中，然后发布到任何流行的 Linux 机器上，也可以实现虚拟化。容器是完全使用沙箱机制，相互之间不会有任何接口（类似 iPhone 的 app），更重要的是容器性能开销极低。&lt;/p&gt;
&lt;p&gt;简而言之&amp;gt; 容器是一个打包了应用服务的环境，它是一个轻量级的虚拟机，每一个容器由一组特定的应用和必要的依赖库组成。&lt;/p&gt;
&lt;p&gt;　　Docker和传统虚拟化之间最大的区别在于：容器是在操作系统层面上实现虚拟化，即直接复用本地主机的操作系统；而传统虚拟化则是在硬件层面实现，如VMware vShpere, Xen及Citrix等。&lt;/p&gt;
&lt;p&gt;1.2 Docker结构 　　Docker 使用客户端-服务器 (C/S) 架构模式，使用远程API来管理和创建Docker容器。 　　Docker 容器通过 Docker 镜像来创建。 　　容器与镜像的关系类似于面向对象编程中的对象与类。　　 　　Docker的架构如下图所示，Client 通过接口与Server进程通信实现容器的构建，运行和发布。Client和Server可以运行在同一台集群，也可以通过跨主机实现远程通信。 &lt;a href=&#34;images/image-1590996351005.png&#34;&gt;&lt;img alt=&#34;image-1590996351005&#34; loading=&#34;lazy&#34; src=&#34;https://dodoro.chouxiangpai.com/archives/956/images/image-1590996351005-300x156.png&#34;&gt;&lt;/a&gt; 　　具体详细内容，请浏览：《几张图帮你理解Docker基本原理及快速入门》&lt;/p&gt;
&lt;h2 id=&#34;二docker的安装&#34;&gt;二、Docker的安装&lt;/h2&gt;
&lt;p&gt;　　（1）准备一台Linux主机，这里以CentOS 7.2为例。当然，你也可以使用Windows，不过你得确保是Windows 10 pro版本及以上，且安装了Hyper-V等一系列的相关软件。&lt;/p&gt;
&lt;p&gt;　　（2）安装docker&lt;/p&gt;
&lt;p&gt;　　# yum install docker&lt;/p&gt;
&lt;p&gt;　　（3）启动docker服务&lt;/p&gt;
&lt;p&gt;　　# systemctl start docker.sevice 　　（4）配置开机启动并验证 　　# systemctl enable docker.service 　　验证：查看docker版本信息 　　# docker version 　　（5）配置docker加速器 =&amp;gt; 原因你懂得，不设置慢死你，云服务器除外&lt;/p&gt;
&lt;p&gt;　　# vim /etc/docker/daemon.json&lt;/p&gt;
&lt;p&gt;{&lt;/p&gt;
&lt;p&gt;&amp;ldquo;registry-mirrors&amp;rdquo;: [&amp;quot;&lt;a href=&#34;https://d8b3zdiw.mirror.aliyuncs.com&#34;&gt;https://d8b3zdiw.mirror.aliyuncs.com&lt;/a&gt;&amp;quot;]&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;　　然后重启docker服务&lt;/p&gt;
&lt;p&gt;　　# systemctl daemon-reload&lt;/p&gt;</description>
    </item>
    <item>
      <title>选择Angular而不是Vue</title>
      <link>https://dodoro.chouxiangpai.com/archives/676/</link>
      <pubDate>Mon, 10 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/676/</guid>
      <description>&lt;p&gt;最近团队要选择前端开发框架，我进行了大量对比，最终选择了Angular，我承认Vue也很优秀，React也超级棒，但Angular非常适合我们。我们需要的就是这样一个真正的框架，包含了组件化方案、模块化方案、测试方案、表单验证、路由、国际化方案和安全方案。&lt;/p&gt;
&lt;p&gt;Angular 的工程师将我们需要的所有功能做了不错的整合。如果使用 Vue，我可能还要面临更多选择。Angular 的一份文档涵盖了开发中的方方面面。如果使用 Vue，可能每个功能要去看不同的文档。Angular 更强势更主观，它的文档对于如何完成某个功能给出了明确的建议。我们团队的成员有不同的编程背景，虽然有三个全职的前端，但是还有十几个 Java 和 Python 程序员，他们也可能会参与前端工作，Angular 的文档能让这些成员快速适应环境。&lt;/p&gt;
&lt;p&gt;Angular = Vue + vue-router + axios + karma + 表单验证插件 + i18n …&lt;/p&gt;
&lt;h2 id=&#34;我们需要typescript来告别原来脓肿不堪的js代码&#34;&gt;我们需要typescript来告别原来脓肿不堪的js代码&lt;/h2&gt;
&lt;p&gt;使用TypeScript，告别对臃肿代码的重构，让自己的编程真正能够面向对象吧。&lt;/p&gt;
&lt;p&gt;一千个人有一千种React代码风格，但是Angular的代码风格只有一种。你会发现Angular的每一处都是最佳实践，设计模式的运用是基于Google多年的Java编程经验的，响应式的应用也是基于微软对于操作系统中异步处理的经验总结。 无数的编程概念都有其历史厚重感，而Angular将他们汇聚到了一起。windows中的linq‘时间上的数组’，spring中的依赖注入，处理HDFS的MR，到linux线程本地存储，再到前端界的MVVM，MVC。&lt;/p&gt;
&lt;p&gt;Angular优势： Angular 的工程师将我们需要的所有功能做了不错的整合。如果使用 Vue，我可能还要面临更多选择。 Angular 的一份文档涵盖了开发中的方方面面。如果使用 Vue，可能每个功能要去看不同的文档。 Angular 更强势更主观，它的文档对于如何完成某个功能给出了明确的建议。我们团队的成员有不同的编程背景，虽然有三个全职的前端，但是还有十几个 Java 和 Python 程序员，他们也可能会参与前端工作，Angular 的文档能让这些成员快速适应环境。 核心原因：Angular 是一个完整的框架。&lt;/p&gt;</description>
    </item>
    <item>
      <title>CentOS编译安装shadowsocks-libev</title>
      <link>https://dodoro.chouxiangpai.com/archives/658/</link>
      <pubDate>Tue, 04 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/658/</guid>
      <description>&lt;p&gt;部署环境：CentOS 7.4 x64&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/shadowsocks/shadowsocks-libev&#34;&gt;shadowsocks-libev项目地址&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;编译安装&#34;&gt;编译安装&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yum update -y
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yum install -y epel-release rng-tools
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yum install -y git wget gettext gcc autoconf libtool automake make asciidoc xmlto c-ares-devel libev-devel zlib-devel openssl-devel
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rngd -r /dev/urandom
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;安装libsodium&#34;&gt;安装Libsodium&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export LIBSODIUM_VER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;1.0.16
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://download.libsodium.org/libsodium/releases/libsodium-$LIBSODIUM_VER.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar xvf libsodium-$LIBSODIUM_VER.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pushd libsodium-$LIBSODIUM_VER
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./configure --prefix&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;popd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ldconfig
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;安装mbedtls&#34;&gt;安装MbedTLS&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export MBEDTLS_VER&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2.7.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://tls.mbed.org/download/mbedtls-$MBEDTLS_VER-gpl.tgz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tar xvf mbedtls-$MBEDTLS_VER-gpl.tgz
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pushd mbedtls-$MBEDTLS_VER
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make SHARED&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; CFLAGS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;-fPIC
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make DESTDIR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;popd
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ldconfig
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;安装shadowsocks&#34;&gt;安装shadowsocks&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/shadowsocks/shadowsocks-libev.git
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd shadowsocks-libev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git submodule update --init --recursive
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./autogen.sh &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./configure &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;make install
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ..
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;修改配置&#34;&gt;修改配置&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir /etc/shadowsocks-libev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vi /etc/shadowsocks-libev/config.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;写入以下内容并保存&lt;/p&gt;</description>
    </item>
    <item>
      <title>安装shadowsocks的v2ray插件</title>
      <link>https://dodoro.chouxiangpai.com/archives/660/</link>
      <pubDate>Tue, 04 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/660/</guid>
      <description>&lt;p&gt;服务端部署 部署环境：CentOS 7.6 x64&lt;/p&gt;
&lt;h2 id=&#34;安装shadowsocks-libev&#34;&gt;安装Shadowsocks-libev&lt;/h2&gt;
&lt;p&gt;这个之前博文说过，就不重复了。&lt;/p&gt;
&lt;h2 id=&#34;安装v2ray-plugin&#34;&gt;安装v2ray-plugin&lt;/h2&gt;
&lt;p&gt;我懒得编译，直接&lt;a href=&#34;https://github.com/shadowsocks/v2ray-plugin&#34;&gt;下载&lt;/a&gt;已经编译好的了，解压到/usr/local/bin/下。&lt;/p&gt;
&lt;h2 id=&#34;获取ssl证书&#34;&gt;获取SSL证书&lt;/h2&gt;
&lt;p&gt;我使用的是Let’s Encrypt的免费证书（这里建议使用CloudFlare的免费证书），执行命令之前记得先将域名的A记录解析到服务器IP上，并且开放80和443端口。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://dl.eff.org/certbot-auto
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod a+x certbot-auto
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./certbot-auto certonly
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;成功之后会有/etc/letsencrypt/live/域名/fullchain.pem和/etc/letsencrypt/live/域名/privkey.pem两个文件。&lt;/p&gt;
&lt;h2 id=&#34;修改配置文件&#34;&gt;修改配置文件&lt;/h2&gt;
&lt;p&gt;默认配置文件在/etc/shadowsocks-libev/config.json，如下文所示，在最后加上plugin和plugin_opts，把域名换成自己的就行。这里采用的是Shadowsocks over websocket (HTTPS)，其它的可以自己参考GitHub上的介绍。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server_port&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;local_port&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;1080&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;timeout&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;method&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;aes-256-gcm&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;plugin&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;v2ray-plugin&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;plugin_opts&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server;tls;cert=/etc/letsencrypt/live/域名/fullchain.pem;key=/etc/letsencrypt/live/域名/privkey.pem;host=域名;loglevel=none&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后执行ss-server -c /etc/shadowsocks-libev/config.json -f /run/shadowsocks.pid即可。&lt;/p&gt;
&lt;h2 id=&#34;客户端设置&#34;&gt;客户端设置&lt;/h2&gt;
&lt;p&gt;先安装对应平台的Shadowsocks客户端。&lt;/p&gt;
&lt;h3 id=&#34;windows&#34;&gt;Windows&lt;/h3&gt;
&lt;p&gt;直接下载已经编译好的v2ray-plugin的windows版，解压后命名为v2ray-plugin.exe和Shadowsocks.exe放在同一文件夹下。 在Shadowsocks的服务器设置中，插件程序填v2ray-plugin，插件选项填tls;host=域名。域名要和服务端设置的一致。&lt;/p&gt;
&lt;h3 id=&#34;android&#34;&gt;Android&lt;/h3&gt;
&lt;p&gt;安装v2ray-plugin-android，打开Shadowsocks编辑服务器，在最下面的插件中选择v2ray，配置Transport mode为websocket-tls，Hostname为服务端设置的域名即可。&lt;/p&gt;
&lt;h3 id=&#34;ubuntu&#34;&gt;Ubuntu&lt;/h3&gt;
&lt;p&gt;直接下载已经编译好的v2ray-plugin，解压到/usr/local/bin/下。 编辑配置文件/etc/shadowsocks-libev/config.json，如下文所示，在最后加上plugin和plugin_opts，域名要和服务端设置的一致。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;域名&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;server_port&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;local_port&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;1080&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;timeout&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;300&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;method&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;aes-256-gcm&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;plugin&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;v2ray-plugin&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;plugin_opts&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tls;host=域名;loglevel=none&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后执行ss-local -c /etc/shadowsocks-libev/config.json即可。&lt;/p&gt;
&lt;h3 id=&#34;优势&#34;&gt;优势&lt;/h3&gt;
&lt;p&gt;你甚至可以把SS服务器放在CDN后面，免费的CDN有Cloudflare。&lt;/p&gt;
&lt;p&gt;然后，最重要的，让你的服务器屏蔽所有除了CloudFlare和你自己的IP之外的所有IP。&lt;/p&gt;
&lt;p&gt;基本上很长一段时间内，G#F#W就拿你没办法了。&lt;/p&gt;
&lt;p&gt;原文: &lt;a href=&#34;https://blog.m3chd09.com/2019/02/01/v2ray-plugin-for-shadowsocks.html&#34;&gt;https://blog.m3chd09.com/2019/02/01/v2ray-plugin-for-shadowsocks.html&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>【转】浅谈我对DDD领域驱动设计的理解</title>
      <link>https://dodoro.chouxiangpai.com/archives/621/</link>
      <pubDate>Wed, 06 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/621/</guid>
      <description>&lt;h1 id=&#34;遇到问题开始&#34;&gt;遇到问题开始&lt;/h1&gt;
&lt;p&gt;当人们要做一个软件系统时，一般总是因为遇到了什么问题，然后希望通过一个软件系统来解决。&lt;/p&gt;
&lt;p&gt;比如，我是一家企业，然后我觉得我现在线下销售自己的产品还不够，我希望能够在线上也能销售自己的产品。所以，自然而然就想到要做一个普通电商系统，用于实现在线销售自己企业产品的目的。&lt;/p&gt;
&lt;p&gt;再比如，我是一家互联网公司，公司有很多系统对外提供服务，面向很多客户端设备。但是最近由于各种原因，导致服务经常出故障。所以，我们希望通过各种措施提高服务的质量和稳定性。其中的一个措施就是希望能做一个灰度发布的平台，这个平台可以提供灰度发布的服务。然后，当某个业务系统做了一些修改并需要发布时，可以使用我们的灰度发布平台来非常方便的实现灰度发布的功能。比如在灰度发布平台上方便的定制允许哪些特定的客户端才会访问新服务，哪些客户端继续使用老服务。灰度发布平台可以提供各种灰度的策略。有了这样的灰度发布机制，那即便系统的新逻辑有什么问题，受影响的面也不会很大，在可控范围内。所以，如果公司里的所有对外提供服务的系统都接入了灰度平台，那这些系统的发布环节就可以更加有保障了。&lt;/p&gt;
&lt;p&gt;总之，我们做任何一个软件系统，都是有原因的，否则就没必要做这个系统，而这个原因就是我们遇到的问题。所以，通过问题，我们就知道了我们需要一个什么样的系统，这个系统解决什么样的问题。最后，我们就很自然的得出了一个目标，即知道了自己要什么。比如我要做一个论坛、一个博客系统、一个电商平台、一个灰度发布系统、一个IDE、一个分布式消息队列、一个通信框架，等等。&lt;/p&gt;
&lt;h1 id=&#34;ddd切入点1---理解概念&#34;&gt;DDD切入点1 - 理解概念&lt;/h1&gt;
&lt;p&gt;DDD的全称为Domain-driven Design，即领域驱动设计。下面我从领域、问题域、领域模型、设计、驱动这几个词语的含义和联系的角度去阐述DDD是如何融入到我们平时的软件开发初期阶段的。要理解什么是领域驱动设计，首先要理解什么是领域，什么是设计，还有驱动是什么意思，什么驱动什么。&lt;/p&gt;
&lt;h2 id=&#34;一什么是领域domain&#34;&gt;一、什么是领域（Domain）？&lt;/h2&gt;
&lt;p&gt;前面我们已经清楚的知道我们现在要做一个什么样的系统，这个系统需要解决什么问题。我认为任何一个系统都会属于某个特定的领域，比如论坛是一个领域，只要你想做一个论坛，那这个论坛的核心业务是确定的，比如都有用户发帖、回帖等核心基本功能。比如电商平台、普通电商系统，这种都属于网上电商领域，只要是这个领域的系统，那都有商品浏览、购物车、下单、减库存、付款交易等核心环节。所以，同一个领域的系统都具有相同的核心业务，因为他们要解决的问题的本质是类似的。&lt;/p&gt;
&lt;p&gt;因此，我们可以推断出，一个领域本质上可以理解为就是一个问题域，只要是同一个领域，那问题域就相同。所以，只要我们确定了系统所属的领域，那这个系统的核心业务，即要解决的关键问题、问题的范围边界就基本确定了。通常我们说，要成为一个领域的专家，必须要在这个领域深入研究很多年才行。因为只有你研究了很多年，你才会遇到非常多的该领域的问题，同时你解决这个领域中的问题的经验也非常丰富。很多时候，领域专家比技术专家更加吃香，比如金融领域的专家。&lt;/p&gt;
&lt;h2 id=&#34;二什么是设计design&#34;&gt;二、什么是设计（Design）？&lt;/h2&gt;
&lt;p&gt;DDD中的设计主要指领域模型的设计。为什么是领域模型的设计而不是架构设计或其他的什么设计呢？因为DDD是一种基于模型驱动开发的软件开发思想，强调领域模型是整个系统的核心，领域模型也是整个系统的核心价值所在。每一个领域，都有一个对应的领域模型，领域模型能够很好的帮我们解决复杂的业务问题。&lt;/p&gt;
&lt;p&gt;从领域和代码实现的角度来理解，领域模型绑定了领域和代码实现，确保了最终的代码实现就一定是解决了领域中的核心问题的。因为：1）领域驱动领域模型设计；2）领域模型驱动代码实现。我们只要保证领域模型的设计是正确的，就能确定领域模型可以解决领域中的核心问题；同理，我们只要保证代码实现是严格按照领域模型的意图来落地的，那就能保证最后出来的代码能够解决领域的核心问题的。这个思路，和传统的分析、设计、编码这几个阶段被割裂（并且每个阶段的产物也不同）的软件开发方法学形成鲜明的对比。&lt;/p&gt;
&lt;h2 id=&#34;三什么是驱动driven&#34;&gt;三、什么是驱动（Driven）？&lt;/h2&gt;
&lt;p&gt;上面其实已经提到了，就是：1）领域驱动领域模型设计；2）领域模型驱动代码实现。这个就和我们传统的数据库驱动开发的思路形成对比了。DDD中，我们总是以领域为边界，分析领域中的核心问题（核心关注点），然后设计对应的领域模型，再通过领域模型驱动代码实现。而像数据库设计、持久化技术等这些都不是DDD的核心，而是外围的东西。&lt;/p&gt;
&lt;p&gt;领域驱动设计（DDD）告诉我们的最大价值我觉得是：当我们要开发一个系统时，应该尽量先把领域模型想清楚，然后再开始动手编码，这样的系统后期才会很好维护。但是，很多项目（尤其是互联网项目，为了赶工）都是一开始模型没想清楚，一上来就开始建表写代码，代码写的非常冗余，完全是过程是的思考方式，最后导致系统非常难以维护。而且更糟糕的是，出来混总是要还的，前期的领域模型设计的不好，不够抽象，如果你的系统会长期需要维护和适应业务变化，那后面你一定会遇到各种问题维护上的困难，比如数据结构设计不合理，代码到处冗余，改BUG到处引入新的BUG，新人对这种代码上手困难，等。而那时如果你再想重构模型，那要付出的代价会比一开始重新开发还要大，因为你还要考虑兼容历史的数据，数据迁移，如何平滑发布等各种头疼的问题。所以，就导致我们最后天天加班。&lt;/p&gt;
&lt;p&gt;虽然，我们都知道这个道理，但是我也明白，人的习惯很难改变的，大部分人都很难从面向过程式的想到哪里写到哪里的思想转变为基于系统化的模型驱动的思维。我想，这或许是DDD很难在中国或国外流行起来的原因吧。但是，我想这不应该成为我们放弃学习DDD的原因，对吧！&lt;/p&gt;
&lt;h2 id=&#34;概念总结&#34;&gt;概念总结：&lt;/h2&gt;
&lt;p&gt;领域就是问题域，有边界，领域中有很多问题；&lt;/p&gt;
&lt;p&gt;任何一个系统要解决的那个大问题都对应一个领域；&lt;/p&gt;
&lt;p&gt;通过建立领域模型来解决领域中的核心问题，模型驱动的思想；&lt;/p&gt;
&lt;p&gt;领域建模的目标针对我们在领域中所关心的问题，即只针对核心关注点，而不是整个领域中的所有问题；&lt;/p&gt;
&lt;p&gt;领域模型在设计时应考虑一定的抽象性、通用性，以及复用价值；&lt;/p&gt;
&lt;p&gt;通过领域模型驱动代码的实现，确保代码让领域模型落地，代码最终能解决问题；&lt;/p&gt;
&lt;p&gt;领域模型是系统的核心，是领域内的业务的直接沉淀，具有非常大的业务价值；&lt;/p&gt;
&lt;p&gt;技术架构设计或数据存储等是在领域模型的外围，帮助领域模型进行落地。&lt;/p&gt;
&lt;h1 id=&#34;ddd切入点2---理解领域拆分领域细化领域&#34;&gt;DDD切入点2 - 理解领域、拆分领域、细化领域&lt;/h1&gt;
&lt;h2 id=&#34;一理解领域知识是基础&#34;&gt;一、理解领域知识是基础&lt;/h2&gt;
&lt;p&gt;上面我们通过第一步，虽然我们明确了要做一个什么样的系统，该系统主要解决什么问题，但是就这样我们还无法开始进行实际的需求分析和模型设计，我们还必须将我们的问题进行拆分，需求进行细化。有些时候，需求方，即提出问题的人，很可能自己不清楚具体想要什么。他只知道一个概念，一个大的目标。比如他只知道要做一个股票交易系统，一个灰度发布系统，一个电商平台，一个开发工具，等。但是他不清楚这些系统应该具体做成什么样子。这个时候，我认为领域专家就非常重要了，DDD也非常强调领域专家的重要性。因为领域专家对这个领域非常了解，对领域内的各种业务场景和各种业务规则也非常清楚，总之，对这个领域内的一切业务相关的知识都非常了解。所以，他们自然就有能力表达出系统该做成什么样子。所以，要知道一个系统到底该做成什么样子，到底哪些是核心业务关注点，只能靠沉淀领域内的各种知识，别无他法。因此，假设你现在打算做一个电商平台，但是你对这个领域没什么了解，那你一定得先去了解下该领域内主流的电商平台，比如淘宝、天猫、京东、亚马逊等。这个了解的过程就是你沉淀领域知识的过程。如果你不了解，就算你领域建模的能力再强，各种技术架构能力再强也是使不上力。领域专家不是某个固定的角色，而是某一类人，这类人对这个领域非常了解。比如，一个开发人员也可以是一个领域专家。假设你在一个公司开发和维护一个系统已经好几年了，但是这个系统的产品经理（PD）可能已经换过好几任了，这种情况下，我相信这几任产品经理都没有比你更熟悉这个领域。&lt;/p&gt;
&lt;h2 id=&#34;二拆分领域&#34;&gt;二、拆分领域&lt;/h2&gt;
&lt;p&gt;上面我们明白了，领域建模的基础是要先理解领域，让自己成为领域专家。如果做到了这点，我们就打好了坚实的基础了。但是，有时一个领域往往太复杂，涉及到的领域概念、业务规则、交互流程太多，导致我们没办法直接针对这个大的领域进行领域建模。所以，我们需要将领域进行拆分，本质上就是把大问题拆分为小问题，然后各个击破的思路。然后既然把一个大的领域划分为了多个小的领域（子域），那最关键的就是要理清每个子域的边界；然后要搞清楚哪些子域是核心子域，哪些是非核心子域，哪些是公共支撑子域；然后，还要思考子域之间的联系是什么。那么，我们该如何划分子域呢？我的个人看法是从业务相关性的角度去思考，也就是我们平时说的按业务功能为出发点进行划分。还是拿经典的电商系统来分析，通常一个电商系统都会包含好几个大块，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h3 id=&#34;会员中心负责用户账号登录用户信息的管理&#34;&gt;会员中心：负责用户账号登录、用户信息的管理；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;商品中心负责商品的展示导航维护&#34;&gt;商品中心：负责商品的展示、导航、维护；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;订单中心负责订单的生成和生命周期管理&#34;&gt;订单中心：负责订单的生成和生命周期管理；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;交易中心负责交易相关的业务&#34;&gt;交易中心：负责交易相关的业务；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;库存中心负责维护商品的库存&#34;&gt;库存中心：负责维护商品的库存；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;促销中心负责各种促销活动的支持&#34;&gt;促销中心：负责各种促销活动的支持；&lt;/h3&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;上面这些中心看起来很自然，因为大家对电子商务的这个领域都已经非常熟悉了，所以都没什么疑问，好像很自然的样子。所以，领域划分是不是就是没什么挑战了呢？显然不是。之所以我们觉得子域划分很简单，是因为我们对整个大领域非常了解了。如果我们遇到一个冷门的领域，就没办法这么容易的去划分子域了。这就需要我们先去努力理解领域内的知识。所以，我个人从来不相信什么子域划分的技巧什么的东西，因为我觉得这个工作没有任何诀窍可以使用。当我们不了解一个东西的时候，如何去拆解它？当我们对整个领域有一定的熟悉了，了解了领域内的相关业务的本质和关系，我们就自然而然的能划分出合理的子域了。不过并不是所有的系统都需要划分子域的，有些系统只是解决一个小问题，这个问题不复杂，可能只有一两个核心概念。所以，这种系统完全不需要再划分子域。但不是绝对的，当一个领域，我们的关注点越来越多，每个关注点我们关注的信息越来越多的时候，我们会不由自主的去进一步的划分子域。比如，也许我们一开始将商品和商品的库存都放在商品中心里，但是后来由于库存的维护越来越复杂，导致揉在一起对我们的系统维护带来一定的困难时，我们就会考虑将两者进行拆分，这个就是所谓的业务垂直分割。&lt;/p&gt;
&lt;h2 id=&#34;三细化子域&#34;&gt;三、细化子域&lt;/h2&gt;
&lt;p&gt;通过上面的两步，我们了解了领域里的知识，也对领域进行了子域划分。但这样还不够，凭这些我们还无法进行后续的领域模型设计。我们还必须再进一步细化每个子域，进一步明确每个子域的核心关注点，即需求细化。我觉得我们需要细化的方面有以下几点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;h3 id=&#34;梳理领域概念梳理出领域内我们关注的概念概念的关系并统一交流词汇形成统一语言&#34;&gt;梳理领域概念：梳理出领域内我们关注的概念、概念的关系，并统一交流词汇，形成统一语言；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;梳理业务规则梳理出领域内我们关注的各种业务规则ddd中叫不变性invariants比如唯一性规则余额不能小于零等&#34;&gt;梳理业务规则：梳理出领域内我们关注的各种业务规则，DDD中叫不变性（invariants），比如唯一性规则，余额不能小于零等；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;梳理业务场景梳理出领域内的核心业务场景比如电商平台中的加入购物车提交订单发起付款等核心业务场景&#34;&gt;梳理业务场景：梳理出领域内的核心业务场景，比如电商平台中的加入购物车、提交订单、发起付款等核心业务场景；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;梳理业务流程梳理出领域内的关键业务流程比如订单处理流程退款流程等&#34;&gt;梳理业务流程：梳理出领域内的关键业务流程，比如订单处理流程，退款流程等；&lt;/h3&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从上面这4个方面，我们从领域概念、业务规则、交互场景、业务流程等维度梳理了我们到底要什么，整理了整个系统应该具备的功能。这个工作我觉得是一个非常具有创造性和有难度的工作。我们一方面会主观的定义我们想要什么；另一方面，我们还会思考我们要的东西的合理性。我认为这个就是产品经理的工作，产品经理必须要负起职责，把他的产品充分设计好，从各个方面去考虑，如何设计一个产品，才能更好的解决用户的核心诉求，即领域内的核心问题。如果对领域不够了解，如果想不清楚用户到底要什么，如果思考问题不够全面，谈何设计出一个合理的产品呢？&lt;/p&gt;
&lt;p&gt;关于领域概念的梳理，我觉得可以采用四色原型分析法，这个分析法通过系统的方法，将概念划分为不同的种类，为不同种类的概念标注不同的颜色。然后将这些概念有机的组合起来，从而让我们可以清晰的分析出概念和概念之间的关系。有兴趣的同学可以在网上搜索下&lt;a href=&#34;http://www.cnblogs.com/netfocus/archive/2011/03/05/1971899.html&#34;&gt;四色原型&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;注意：上面我说的这四点，重点是梳理出我们要什么功能，而不是思考如何实现这些功能，如何实现是软件设计人员的职责。&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id=&#34;ddd切入点3---领域模型设计&#34;&gt;DDD切入点3 - 领域模型设计&lt;/h1&gt;
&lt;p&gt;这部分内容，我想学习DDD的人都很熟悉了。DDD原著中提出了很多实用的建模工具：聚合、实体、值对象、工厂、仓储、领域服务、领域事件。我们可以使用这些工具，来设计每一个子域的领域模型。最终通过领域模型图将设计沉淀下来。要使用这些工具，首先就要理解每个工具的含义和使用场景。不要以为很简单哦，比如聚合的划分就是一个非常具有艺术的活。同一个系统，不同的人设计出来的聚合是完全不同的。而且很有可能高手之间的最后设计出来的差别反而更大，实际上我认为是世界观的相互碰撞，呵呵。所以，要领域建模，我觉得每个人都应该去学学哲学知识，这有助于我们更好的认识世界，更好的理解事物的本质。&lt;/p&gt;
&lt;p&gt;关于这些建模工具的概念和如何运用我就不多展开了，我博客里也有很多这方面的介绍。下面我再讲一下我认为比较重要的东西，比如到底该如何领域建模？步骤应该是怎么样的？&lt;/p&gt;
&lt;h2 id=&#34;一领域建模的方法&#34;&gt;一、领域建模的方法&lt;/h2&gt;
&lt;p&gt;通过上面我介绍的细化子域的内容，现在再来谈该如何领域建模，我觉得就方便很多了。我的主要方法是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;h3 id=&#34;划分好边界上下文通常每个子域sub-domain对应一个边界上下文bounded-context同一个边界上下文中的概念是明确的没有任何歧义&#34;&gt;划分好边界上下文，通常每个子域（sub domain）对应一个边界上下文（bounded context），同一个边界上下文中的概念是明确的，没有任何歧义；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;在每个边界上下文中设计领域模型具体的领域模型设计方法有很多种如以场景为出发点的四色原型分析法或者我早期写的这篇文章这个步骤最核心的就是找出聚合根并找出每个聚合根包含的信息关于如何设计聚合可以看一下我写的这篇文章&#34;&gt;在每个边界上下文中设计领域模型，具体的领域模型设计方法有很多种，如以场景为出发点的&lt;a href=&#34;http://www.cnblogs.com/netfocus/archive/2011/03/05/1971899.html&#34;&gt;四色原型&lt;/a&gt;分析法，或者我早期写的这篇&lt;a href=&#34;http://www.cnblogs.com/netfocus/archive/2011/09/18/2180656.html&#34;&gt;文章&lt;/a&gt;；这个步骤最核心的就是找出聚合根，并找出每个聚合根包含的信息；关于如何设计聚合，可以看一下我写的&lt;a href=&#34;http://www.cnblogs.com/netfocus/p/3307971.html&#34;&gt;这篇文章&lt;/a&gt;；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;画出领域模型图圈出每个模型中的聚合边界&#34;&gt;画出领域模型图，圈出每个模型中的聚合边界；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;设计领域模型时要考虑该领域模型是否满足业务规则同时还要综合考虑技术实现等问题比如并发问题领域模型不是概念模型概念模型不关注技术实现领域模型关心所以领域模型才能直接指导编码实现&#34;&gt;设计领域模型时，要考虑该领域模型是否满足业务规则，同时还要综合考虑技术实现等问题，比如并发问题；领域模型不是概念模型，概念模型不关注技术实现，领域模型关心；所以领域模型才能直接指导编码实现；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;思考领域模型是如何在业务场景中发挥作用的以及是如何参与到业务流程的每个环节的&#34;&gt;思考领域模型是如何在业务场景中发挥作用的，以及是如何参与到业务流程的每个环节的；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;场景走查确认领域模型是否能满足领域中的业务场景和业务流程&#34;&gt;场景走查，确认领域模型是否能满足领域中的业务场景和业务流程；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;模型持续重构完善精炼&#34;&gt;模型持续重构、完善、精炼；&lt;/h3&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;二领域模型的核心作用&#34;&gt;二、领域模型的核心作用：&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;h3 id=&#34;抽象了领域内的核心概念并建立概念之间的关系&#34;&gt;抽象了领域内的核心概念，并建立概念之间的关系；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;领域模型承担了领域内的状态的维护&#34;&gt;领域模型承担了领域内的状态的维护；&lt;/h3&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h3 id=&#34;领域模型维护了领域内的数据之间的业务规则数据一致性&#34;&gt;领域模型维护了领域内的数据之间的业务规则，数据一致性；&lt;/h3&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要特别注意的是，领域模型设计只是整个软件设计中的很小一部分。除了领域模型设计之外，要落地一个系统，我们还有非常多的其他设计要做，比如：&lt;/p&gt;</description>
    </item>
    <item>
      <title>互联网架构启示：一根网线引发的“血案”</title>
      <link>https://dodoro.chouxiangpai.com/archives/583/</link>
      <pubDate>Thu, 13 Aug 2015 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/583/</guid>
      <description>&lt;p&gt;&lt;strong&gt;互联网架构启示：一根网线引发的“血案”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;引言：当一个网站做大的时候，无论是研发还是运维，每一个细节都至关重要，网站的任何一个小的瑕疵都会被无限放大。&lt;/p&gt;
&lt;p&gt;公司有一个基于微信公共服务器号开发的产品，主要为微信用户提供在线交流、互动、阅读和科研分析等功能。前阵子升级了支付接口，运营人员开始用红包推广，并且把原来微信服务号的积累的用户引流到服务号本身的网站服务，网站堵塞时秒并发连接数峰值达到1k，数据库瞬间批处理数也达到了2k+，这个量其实不算什么，但因为运维架构的一个疏忽，导致网站2次宕机。这里先说明两点：运维属于公司另外一个部门，当然大家还是相互协作还算比较好；我们的服务器都是32G内存，4核2GHz的CPU的品牌服务器。&lt;/p&gt;
&lt;p&gt;第一次宕机：抢红包导致宕机3小时。&lt;/p&gt;
&lt;p&gt;我们发布完毕2.0版本之后，运营很开心，打算搞一次庆祝活动：只要来关注公共号，进入首页就可以另一个1块钱红包，任何人都可以。发红包当天，我没有接到通知，到家收到微信的提醒，过了差不多1小时，运营电话过来说网站慢了，而此时我连服务器都很难连接不上，运维的说50兆的带宽只用了8兆（这里有一个细节他没有告诉我：网络是一条几乎是直线在运行），再过来半小时，网站几乎打不开了。过了一阵子我登录终于能登录服务器了，但还是很卡，看了服务器的指标，我关注了io、cpu和内存，发现全部正常，idle很高，几乎都是80%，不过没有注意网络。接着两个多小时，直到红包抢完，网站才开始能正常访问。第二天，运维与我们完成了负载均衡的搭建，4台web，1台专用db，cache不变，与架构变化之前一样，只做了web服务器级别的cache，我个人判断这样的量还不需要加memcached和读写分离。后面两次发红包量没有那么大，服务器都正常，但我观察了服务器，发现一个现象：当并发数比较多的时候，db服务器指标还是正常，但总有点卡顿，这次我观察到有时候内外的网络会瞬间冲到98MB，咨询运维的同事说这个正常我们内网有千兆网卡呢，而且现在外网的流量不到占用不到10%。&lt;/p&gt;
&lt;p&gt;第二次宕机：活动导入流量导致宕机1小时。&lt;/p&gt;
&lt;p&gt;这一次宕机，我觉得不可能发生的。当天傍晚，运营的人一下子给微信十万级别的用户发消息，把他们引流进入网站，过了1小时网站又宕机了，一直过了高峰才恢复，那天只有运维的人在跟服务器情况。第二天，运维的跟我说是我们数据库有问题，他们的理由是：外网流量还是一条7MB直线，所有服务器的指标都正常，但是一拔数据库的网线整个网际通了，所以是db处理不过来那么多请求、或者代码有问题。我当时有点懵了，因为看了流量，那天2个小时的pv达到了10w，鉴于这个产品我们使用了比较新的开发框架，我开始怀疑代码问题、数据库连接问题等等。然后先把所有能优化的都优化，包括动态的内容等也加cache，上了1台memcached服务器。我们还把用户行为用消息队列进行异步处理。改完之后开始google，研究程序架构支撑情况、数据库并发数等等，结论是感觉昨晚的量在昨晚这种条件下网站不应该宕机的，我甚至都怀疑是不是服务器采购的时候被动手脚了-_-&lt;/p&gt;
&lt;p&gt;过了一周运营再次搞活动，活动之前我还发现一个问题：个别图书封面居然有5mb的图片，原来产品经理为了让用户看清楚图书封面要求用原图，我赶紧让工程师改成压缩图片。晚上刚到家不久，运营电话又过来了，说虽然没有宕机，内容也能看，但还是有点慢。我接到电话觉得很不可思议，心里想怎么流量那么高。登录服务器之后，发现流量也就是和上次一样，症状和上次也是一样，和运维的沟通，说他连不上服务器（网络是正常的），我特地看了db的连接也只有2位数，虽然偶尔会突然到2k多，但我知道这是因为网络堵住连接不到memcached。当天晚上就咨询以前的认识的运维大拿们，他们也觉得很不可思议，但我们判断肯定是硬件架构哪里出了问题，我把服务器的指标等都截图保留。公司运维的哥们这时候说怀疑是内外网公用网卡的原因，不过这种做法也不是不可以，因为内网有千兆网卡。第二天，又咨询了很多人，大家的结论是：网络有问题。问了好几次公司运维，都说：交换机是千兆的、防火墙是千兆的、网卡是千兆的，后来我以前的同事乌咔咔大拿注意到我截图里面显示网卡只有100MB，我赶紧检查所有的服务器，发现：内外网公用一个只有100MB的网卡！！！问了运维，他说网卡肯定是千兆，我说是不是被自适应了，他楞了一下，说不是自适应，是网线可能是百兆的，去机房确认了一下，发现服务器用的全是5类网线，而且是自己做的……运维也知道是啥原因了，走了特批买了超6类的网线换上。&lt;/p&gt;
&lt;p&gt;目前网站一切正常，未来如果突破一定的用户量，肯定要做db的读写分离、cdn等。回过头来看，第一次宕机的可能性很多种，网线问题、web服务器超并发问题、db和web在同一台问题等；第二次宕机的原因应该是：这根网线引发，内网网络瞬间被挤爆，所有内部通信在等待、数据库连接超时，我的理由是这一天的秒连接数也只有几百，数据库连接也就1k多；第三次虽然没有宕机，但网站有些慢，依然是因为这根网线的原因。&lt;/p&gt;
&lt;p&gt;这就是一根网线引发的“血案”的案例，希望对看到的工程师们有所帮助。我本人一直做开发，也自认为自己开发能力、软件系统架构能力很强，但之前确实忽略了硬件方面的知识，这一次是彻彻底底、从头到尾上了一个课。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Memcached简介及相关访问客户端</title>
      <link>https://dodoro.chouxiangpai.com/archives/176/</link>
      <pubDate>Mon, 22 Oct 2012 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/176/</guid>
      <description>&lt;p&gt;  Memcached是一个高性能的分布式内存对象缓存系统，用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数，从而提供动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程（daemon ）是用C写的，但是客户端可以用任何语言来编写，并通过memcached协议与守护进程通信。&lt;/p&gt;
&lt;p&gt;  Memcached：是守护程序，也就是服务端，它与分布式无关，它的下载地址是&lt;a href=&#34;http://memcached.org/&#34;&gt;http://memcached.org/&lt;/a&gt;；&lt;/p&gt;
&lt;p&gt;  Memcached的客户端：客户端是指通过各种语言（php、java、.net）访问Memcached服务端，客户端实现了分布式算法，这里需要注意，php有两个访问memcahced的客户端&lt;/p&gt;
&lt;p&gt;   php其中一个客户端是：memcache（下载地址：&lt;a href=&#34;http://php.net/manual/en/book.memcache.php&#34;&gt;http://php.net/manual/en/book.memcache.php&lt;/a&gt;），直接使用这个客户端的memcache.so或者memcache.dll文件就可以连接到Memcached服务端，不需要额外的其他组件，不过这个客户端的功能比较差，不支持CAS操作等；&lt;/p&gt;
&lt;p&gt;   php另外一个客户端是：memcached（下载地址：&lt;a href=&#34;http://php.net/manual/en/book.memcached.php&#34;&gt;http://php.net/manual/en/book.memcached.php&lt;/a&gt;），使用这个客户端，需要在客户端上安装libmemcached（下载地址：&lt;a href=&#34;http://libmemcached.org/libMemcached.html&#34;&gt;http://libmemcached.org/libMemcached.html&lt;/a&gt;）客户端，然后再引用memcached.so或者memcached.dll，这个客户端支持大量的操作，而且也非常稳定，建议使用这个客户端。&lt;/p&gt;</description>
    </item>
    <item>
      <title>ios客户端开发使用框架</title>
      <link>https://dodoro.chouxiangpai.com/archives/122/</link>
      <pubDate>Sun, 12 Aug 2012 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/122/</guid>
      <description>&lt;p&gt;这个月开始重启ios客户端的研发，之前做过一个图书软件，这次要做一个学术在线的客户端。&lt;br&gt;
这次用到了如下一些框架：&lt;br&gt;
&lt;strong&gt;FMDB&lt;/strong&gt;：一款轻量级的访问sqllite类库，非常强大 ，FMDB将SQLite API进行了很友好的封装，使用上非常方便，对于那些使用纯Sqlite API来进行数据库操作的app，可以考虑将其迁移到基于FMDB上，这对于以后数据库相关功能的开发维护，可以提高不少效率。&lt;br&gt;
&lt;strong&gt;ASIHTTPRequest&lt;/strong&gt;：一款访问网络的类库，支持断点续传。 ASIHTTPRequest就是一个对CFNetwork API进行了封装，并且使用起来非常简单的一套API，用Objective-C编写，可以很好的应用在Mac OS X系统和iOS平台的应用程序中。ASIHTTPRequest适用于基本的HTTP请求，和基于REST的服务之间的交互。&lt;br&gt;
**cocoa-aes：**一款进行进行aes加密解密的类库，我自己做了封装，支持aes的128对称加密算法。&lt;/p&gt;</description>
    </item>
    <item>
      <title>面向对象必知：继承本质论</title>
      <link>https://dodoro.chouxiangpai.com/archives/39/</link>
      <pubDate>Mon, 21 May 2012 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/39/</guid>
      <description>&lt;p&gt;每个人开始学习面向对象的时候，基本上都感觉自己很能理解什么是“继承”，可是我相信没有多少个人是真正地理解了“继承的本质”。 继承，就是面向对象中的类与类直接的关系，继承的类叫做子类或者派生类，而被继承的泪叫做父类、基类或者超类。通过继承，子类可以拥有父类的属性、方法，同时子类也可以添加新的属性或者方法，还可以修改父类的方法和属性等。 在《你必须知道的.NET》中，作者列举了下面几个关于继承的要点： 1、继承是可以传递的，子类是对父类的扩展，必须继承父类方法，同时可以添加新方法； 2、子类可以调用父类的方法、属性和字段，但是父类不能够调用子类的方法、属性和字段； 3、虚方法如何实现覆写操作，使得父类指针可以指向子类对象成员； 4、子类不仅继承了父类公共成员，也继承了私有成员，只是在子类中不被访问； 5、new在虚方法继承中起阻断作用。 上面这五条几乎可以说是继承的本质，深刻理解了这些，基本可以说对继承掌握了，不过还有一个比较重要的地方需要注意，请看： #region 深入理解继承机制、多态、封装 public abstract class Animal { public abstract void ShowType(); public void Eat() { Console.WriteLine(&amp;ldquo;All Animals need eating!&amp;rdquo;); } } public class Bird : Animal { private string type = &amp;ldquo;Bird&amp;rdquo;; public override void ShowType() { Console.WriteLine(&amp;ldquo;Type is {0}&amp;rdquo;, type); } private string color; public string Color { get { return this.color; } set { this.color = value; } } } public class Chicken : Bird { private string type = &amp;ldquo;Chicken&amp;rdquo;; public override void ShowType() { Console.WriteLine(&amp;ldquo;Type is {0}&amp;rdquo;, type); } public void ShowColor() { Console.WriteLine(&amp;ldquo;Color is {0}&amp;rdquo;, Color); } } #endregion 上面是定义了一个抽象父类和两个子类，下面是调用方法： #region 深入理解OO思想 //Bird bird 创建的是一个Bird类型的引用，而new Bird()完成的是创建Bird对象，分配内存空间和初始化操作 Bird bird = new Bird(); Chicken chicken = new Chicken(); Bird bird2 = new Chicken();//请注意上面这里的区别 bird.ShowType(); chicken.ShowType(); bird2.ShowType(); #endregion 如果你能够了解为什么上面得到的结果，你就深刻理解了什么是继承了&lt;/p&gt;</description>
    </item>
    <item>
      <title>面向对象必知：深入理解对象</title>
      <link>https://dodoro.chouxiangpai.com/archives/37/</link>
      <pubDate>Sat, 21 May 2011 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/37/</guid>
      <description>&lt;p&gt;上一节讲到了类，这次讲对象。一个类可以创建对象，对象可以操作类里面的方法，也可以操作类从父类继承的合法方法，还可以操作其他类的共用方法。 在程序设计（这里都以C#语言为准）中的对象和人类世界中的是类似的，人类世界中每一个人都是一个对象，一个人有自己的姓名、身高等属性，一个人可以做很多事情，也受到很多约束；而程序设计里的对象就是模拟了人类世界的对象，一个对象必须要创建，这个对象在创建之时就确定了它的属性，这个对象可以有很多方法，这个对象受到访问权限的约束。 人类生活在人类社会这个时间里，而对象生存在.NET中的CLR环境；人类在社会里受到法律、风俗等约束，对象在CLR里也同样有着自己的一套约定，比如类型、语法等。 对象最为重要的是：有自己的属性（有如一个人的属性）、有自己可以访问的方法（有如一个人可以做的事情）、访问权限（有如一个人做什么事情受到的权限限制）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>面向对象程序设计必知：深入理解类</title>
      <link>https://dodoro.chouxiangpai.com/archives/35/</link>
      <pubDate>Fri, 21 May 2010 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/35/</guid>
      <description>&lt;p&gt;人以类聚”，这个成语说明了类的概念，在面向对象设计中的类也是如此，一个类是一组东西的抽象，类可以有抽象出来的类（抽象类），也可以是具体的类，抽象类往往都有具体类，具体类负责实现抽象类定义的方法。一个类，里面定义了属于这个类别的东西共同拥有的属性和方法，比如Duck鸭子类，里面有叫声，羽毛等鸭子都有的属性，有游泳，叫等鸭子都有的方法。 在C#里类还分静态类和非静态类，最大的区别是静态类里必须都是静态方法，静态类必须用类名去访问里面的方法，静态类是编译时就确定的；非静态类必须先创建一个实例对象，然后才能去访问类里的成员和方法，非静态类是动态绑定的，也就是在执行的时候才确定要执行什么方法。 类有修饰它的关键字：Public、Protected，Private。这几个关键字代表的意思是： 1、Public：公共的类，这个类可以在外面的类被访问到； 2、Protected：私有的类，这个类可以在继承它的类被访问到； 3、Private：私有的类，这个类不能在任何其他外面的被类访问到。&lt;/p&gt;</description>
    </item>
    <item>
      <title>什么叫设计模式</title>
      <link>https://dodoro.chouxiangpai.com/archives/89/</link>
      <pubDate>Thu, 21 May 2009 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/89/</guid>
      <description>&lt;p&gt;现在网上有大量的文章写设计模式，无论是Gof的23种设计模式，还是其他自己创造处理的模式，但是在做这些工作之前应该深入理解什么叫设计模式。 总的来说，设计模式是一各个编程套路，类似于建筑设计，网上也有关于什么叫设计模式的经典分析，下面仅仅作为摘要简述： 1、来自豆瓣网的声音： 设计模式并不是什么新的东西。有些模式，你或许已经在实际项目中应用了很多年了，只是不知道人家原来是这么称呼它的！ 2、来自博客园的分析： 设计模式就是解决问题的一种方式，每一个模式描述了一个在我们周围不断重复发生的问题，以及该问题的解决方案的核心。这样你就可以一次又一次的使用该解决方案而不做重复性的劳动。设计模式有四个基本要素：模式名称、问题、解决方案、效果。 按照模式的目的性准则，模式可以分为创建型模式、结构型模式和行为型模式。创建型模式与对象的创建有关；结构型模式处理类和对象的组合；行为型模式对类和对象怎样交互和怎样分配职责进行描述。 按照模式的范围准则，模式可以分为类模式和对象模式。类模式处理类和子类的关系，这些关系通过继承建立，是静态的，在编译时就确定下来。对象模式是处理对象之间的关系，这些关系在运行时刻是可以变化的，更具动态性。 创建型类模式将对象的创建工作部分延迟到子类。创建型对象模式则是将它延迟到另一个对象中。 结构型类模式使用继承机制来组合类。结构型对象模式则描述了对象的组装方式。 行为型类模式使用继承描述算法和控制流。行为型对象模式描述使用一组对象怎样协作完成单个对象无法完成的任务。&lt;/p&gt;</description>
    </item>
    <item>
      <title>关于Web性能分析和大型网站架构设计</title>
      <link>https://dodoro.chouxiangpai.com/archives/85/</link>
      <pubDate>Thu, 21 May 2009 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/85/</guid>
      <description>&lt;p&gt;对于网站的理解，不同层次的人有不同的理解。一个网站可以简单地只有几个静态页面，花上一两个小时的时间就可以做好；但是也可能设计地非常精巧，能够承受亿万级的访问量，这样的网站设计起来就很复杂，而且会耗掉大量的人力物力。简单的网站提供的功能是有限的，作用也很小；但是对于大型的网站，就非常地有用，可以提供丰富多彩的功能，比如Google、百度、淘宝、新浪、搜狐等这些网站。 所有的网站开发人员都希望能够设计出性能稳定、负载能力大的网站，而一个对于web系统：最大的瓶颈是数据库；展现效率的决定性因素是前端调用和架构；系统健壮性的决定性因素是总体架构。 1、Web系统最大瓶颈是数据库 无论是使用哪类数据库管理软件（DB2、SQL Server、Oracle），数据库瓶颈是让网站开发者最为头痛的，每一次数据库连接操作都会消耗极大的系统资源（CPU资源、磁盘IO资源等），如果并发达到百万级，没有合理的数据库访问策略，那么网站肯定马上就瘫痪。解决这一问题，主要靠缓存机制，而在数据库缓存里最好用的莫过于Memcached（非常高效的分布式数据库缓存工具），有了Memcached，那么就可以大量地减少数据库链接数，而且可以进行分布式，极大了减小了数据库的压力，而且可以随时增加服务器扩充数据库负载能力。当然Memcached并非绝对灵丹妙药，必须在网站架构和程序代码上下功夫，比如数据库读写分离、缓存更新机制等。Memcached是针对Linux操作系统的，在Windows下也可以用，但并不一定能够达到很好的效果，幸运的是微软现在也自己开发了一套类似的东西：Velocity。 2、展现效率的决定性因素是前端调用和架构 如果你认真去分析淘宝网的页面代码，你就会发现这句话一点都没有错，当服务器响应快速了之后，如何能够展现地更快，就是前端优化，淘宝的前端开发工程师曾说过：页面响应80%时间来自js、css和html代码，由此可见前端的重要性。对于css和div，在兼容浏览器的前提下，最好能够尽量向web标准靠拢，对于js，我建议是使用稳定的js框架，个人喜欢JQuery。 3、系统健壮性的决定性因素是总体架构 网站的总体架构相当于一个人的骨架，没有好的架构不用提稳定性了。一个好的网站架构应该满足：三层（表现、逻辑、数据访问）分离、代码规范、可扩充，如果是大型网站，还要是分布式的、数据库读写分离。&lt;/p&gt;</description>
    </item>
    <item>
      <title>网站被黑原因,sql注入式攻击,网站挂马防范</title>
      <link>https://dodoro.chouxiangpai.com/archives/87/</link>
      <pubDate>Thu, 21 May 2009 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/87/</guid>
      <description>&lt;p&gt;1、网站被黑的原因 此次我们网站遭到的是sql注入攻击，具体攻击目标是数据库中存放2009年1月份数据表，黑客修改了这张表的一个字段的信息，导致了我们网站被嵌入带有威胁的js代码。 2、解决办法 到目前为止，我们已经把整个数据库的所有记录信息都进行了排查、消除了所有带有危害的数据，我们也已经把所有容易受到攻击的端口关闭（ftp的21端口）、并重新设置数据库的用户名和密码；另外，开发人员和系统人员都在努力寻找和修补在Web服务器上可能存在的sql注入漏洞。 3、未来防范策略 （1）、严格限制对sql server数据库的访问权限； （2）、对网站的sql语句进行全面排查，确保所有对数据库请求操作都进行字符串过滤； （3）、关闭除了80和443以外的其他所有端口； （4）、定期对数据库最可能受攻击的数据进行安全检查。&lt;/p&gt;</description>
    </item>
    <item>
      <title>设计模式：单件模式C#实现,源代码</title>
      <link>https://dodoro.chouxiangpai.com/archives/93/</link>
      <pubDate>Thu, 21 May 2009 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/93/</guid>
      <description>&lt;p&gt;单件模式属于创建型模式，创造性模式主要是关注于如何以及何时创建对象。Singleton 模式可以保证一个类有且只有一个实例，并提供一个访问它的全局访问点。在程序设计过程中，有很多情况需要确保一个类只能有一个实例。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;namespace&lt;/span&gt; Singleton.Design.Pattern
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Main(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] args)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//Singleton e = new Singleton(); 这是错误的，因为已经设定为保护类型了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Singleton instance = Singleton.Instance();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;instance.Show();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.ReadKey();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Singleton&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Singleton instance;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;protected&lt;/span&gt; Singleton()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; Singleton Instance()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (instance == &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;instance = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Singleton();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; instance;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Show()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Singleton is Show now!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>设计模式：抽象工厂模式C#实现,源代码</title>
      <link>https://dodoro.chouxiangpai.com/archives/95/</link>
      <pubDate>Thu, 21 May 2009 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/95/</guid>
      <description>&lt;p&gt;前一篇文章介绍了简单工厂和工厂方法模式,这次讨论抽象工厂模式。 1、抽象工厂模式定义 抽象工厂模式也叫Abstract Factory模式，是由GoF提出的23种设计模式中的一种，也是对象创建型模式之一。它提供一个创建一系列相关或相互依赖对象的接口，而无需指定它们具体的类。它提供一个接口，以创建多个相关联的对象，而无需具体指定其具体的类。形象地说，它是一个工厂，能够生产众多产品。当用户需要某种产品的时候，不需要去关心这个产品的具体实现，而只需要指定产品的名称，抽象工厂就能够按你的要求进行生产。这里所指的产品，在C#中我们代表的是一个实例的类。 2、在什么情况下使用抽象工厂模式 在面向对象的程序设计中，我们经常会定义许多类，并通过new对其进行实例化。一旦类对象较多，且在实例化的时候，要做的初始化工作比较复杂的时候，我们就可以通过抽象工厂来管理。根据对象的性质和内容分别抽象成类，同时定义接口和接口方法。一旦定义了抽象工厂，实例类的工作就交给工厂，使用者只需要告诉工厂，你实例化的对象是什么就行了。 3、抽象工厂模式实现原理 抽象工厂模式（Abstract Factory）强调的是对象组合机制，由在父工厂内定义不同的“子工厂”对象来负责不同的目标对象的创建。请注意下面要点： （1）、 抽象工厂模式中，产品（目标对象）的使用者可能需要使用具体的子工厂来生成该产品； （2）、抽象工厂模式采用传参数的形式直接在父工厂内决定该产品对象应该由哪一个子工厂生产。即Abstract Factory模式中，跟客户打交道的只有抽象工厂与抽象产品，客户不需要知道产品由哪个工厂生产，也不需要知道被生产的是哪一种具体的产品； （3）、Factory Method模式中，省城的对象产品只限定于某一类产品；Abstract Factory模式则可以提供多个生产接口生成多类产品； （4） 、Abstract Factory模式Factory Method模式的更高层次的抽象，也更最具一般性。可以把Factory Method模式看作是Abstract Factory模式的一种特殊情况。 4、C#实现代码 using System; using System.Collections.Generic; using System.Text; namespace AbstractFactory.Design.Pattern { class Program { static void Main(string[] args) { IAbstratFactory factory1 = new ConcreteFactory1(); IAbstratFactory factory2 = new ConcreteFactory2(); Evironment e1 = new Evironment(factory1); Evironment e2 = new Evironment(factory2); e1.Show(); e2.Show(); e1.Run(); e2.Run(); Console.ReadKey(); } } //抽象产品 public interface IAbstractProduceA { void MakeProduce(); } public interface IAbstractProduceB { void InterTract(IAbstractProduceA a); } //具体产品 public class ProduceA1:IAbstractProduceA { public void MakeProduce() { Console.WriteLine(&amp;ldquo;ProduceA1 is Created now!&amp;rdquo;); } } public class ProduceB1 : IAbstractProduceB { public void InterTract(IAbstractProduceA a) { Console.WriteLine(this + &amp;quot; contact with &amp;quot; + a); } } public class ProduceA2 : IAbstractProduceA { public void MakeProduce() { Console.WriteLine(&amp;ldquo;ProduceA2 is Created now!&amp;rdquo;); } } public class ProduceB2 : IAbstractProduceB { public void InterTract(IAbstractProduceA a) { Console.WriteLine(this+&amp;quot; contact with &amp;ldquo;+a); } } //抽象工厂 public interface IAbstratFactory { IAbstractProduceA CreateProduceA(); IAbstractProduceB CreateProduceB(); } //具体工厂 public class ConcreteFactory1 : IAbstratFactory { public IAbstractProduceA CreateProduceA() { return new ProduceA1(); } public IAbstractProduceB CreateProduceB() { return new ProduceB1(); } } public class ConcreteFactory2 : IAbstratFactory { public IAbstractProduceA CreateProduceA() { return new ProduceA2(); } public IAbstractProduceB CreateProduceB() { return new ProduceB2(); } } //客户端 public class Evironment { private IAbstractProduceA abstractProdueA; private IAbstractProduceB abstractProdueB; public Evironment(IAbstratFactory factory) { abstractProdueA = factory.CreateProduceA(); abstractProdueB = factory.CreateProduceB(); } public void Show() { abstractProdueA.MakeProduce(); } public void Run() { abstractProdueB.InterTract(abstractProdueA); } }&lt;/p&gt;</description>
    </item>
    <item>
      <title>设计模式：简单工厂和工厂方法的C#实现</title>
      <link>https://dodoro.chouxiangpai.com/archives/91/</link>
      <pubDate>Thu, 21 May 2009 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/91/</guid>
      <description>&lt;p&gt;设计模式中工厂方法包括了：简单工厂，工厂方法和抽象工厂，下面给出简单工厂和工厂方法的C#实现，你可以直接拷贝运行。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-csharp&#34; data-lang=&#34;csharp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;namespace&lt;/span&gt; Factory.Design.Pattern
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Program&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; Main(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;[] args)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//设计模式之简单工厂&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//LightSimpleFactory lsf = new LightSimpleFactory();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//Light lsb= lsf.Create(&amp;#34;Blue&amp;#34;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//Light lsr = lsf.Create(&amp;#34;Red&amp;#34;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//lsb.TurnOn();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//lsr.TurnOn();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//设计模式之工厂方法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CreatorMethod cb = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; BlueCreator();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CreatorMethod cr = &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RedCreator();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Light lb = cb.factory();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Light lr = cr.factory();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lb.TurnOn();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lr.TurnOn();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.ReadKey();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Light&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; TurnOn();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BlueLight&lt;/span&gt; : Light
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; TurnOn()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Blue Light is turn on!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RedLight&lt;/span&gt; : Light
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt; TurnOn()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Console.WriteLine(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Red Light is turn on!&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#region&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;简单工厂&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;LightSimpleFactory&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; Light Create(&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; LightType)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; (LightType)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Blue&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; BlueLight();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Red&amp;#34;&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RedLight();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;null&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#endregion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#region&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;工厂方法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;CreatorMethod&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;abstract&lt;/span&gt; Light factory();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BlueCreator&lt;/span&gt; : CreatorMethod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; Light factory()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; BlueLight();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;RedCreator&lt;/span&gt; : CreatorMethod
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;override&lt;/span&gt; Light factory()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; RedLight();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#endregion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>面向对象思想研究心得体会</title>
      <link>https://dodoro.chouxiangpai.com/archives/33/</link>
      <pubDate>Thu, 21 May 2009 00:00:00 +0000</pubDate>
      <guid>https://dodoro.chouxiangpai.com/archives/33/</guid>
      <description>&lt;p&gt;&lt;strong&gt;封装、继承、多态&lt;/strong&gt;，这三个是面向对象最重要的概念，抽象则是灵魂与核心。但是真正的面向对象决不是通过简单的继承、通过实现简单的多态来实现的，面向对象的核心在于它的几个指导原则（单一职责原则，接口隔离原则，依赖倒置原则，Liskov原则，开发封闭原则）下设计出相互作用的类。&lt;/p&gt;
&lt;p&gt;面向对象还有两个特别的名词：&lt;strong&gt;类，对象&lt;/strong&gt;。类与类之间的相关联系（聚合、泛化、依赖、关联），对象与对象之间的转换关系，这两者是真正考验一个人面向对象设计能力的指标。&lt;/p&gt;
&lt;p&gt;在一个面向对象系统中，大量的类在一起，它们不可能都没有相互关系，如果这样的话就无法完成优秀的面向对象设计架构。在C#中，对象与之间的关系，主要在于处理好父类对象和之类对象之间的引用关系。&lt;/p&gt;
&lt;p&gt;1、&lt;strong&gt;单一职责原则&lt;/strong&gt;：一个类，最好只做一件事，只有一个引起它变化的原因；&lt;/p&gt;
&lt;p&gt;2、&lt;strong&gt;开放封闭原则&lt;/strong&gt;：软件实体应该是可扩展，而不可修改的。也就是说扩展是开放的，修改是封闭的；&lt;/p&gt;
&lt;p&gt;3、&lt;strong&gt;依赖倒置原则&lt;/strong&gt;：依赖于抽象，而不是依赖与具体；&lt;/p&gt;
&lt;p&gt;4、&lt;strong&gt;接口隔离原则&lt;/strong&gt;：使用多个小的专门的接口，而不要使用一个大的总接口；&lt;/p&gt;
&lt;p&gt;5、&lt;strong&gt;Liskov原则&lt;/strong&gt;：子类必须能够替换其基类。 以上这五个原则在面向对象设计中非常关键，只有灵活地运用了才可以真正地掌握好面向对象思想。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
