<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>设计模式 归档 - 初晴神社</title>
	<atom:link href="https://vki.cc/tag/%e8%ae%be%e8%ae%a1%e6%a8%a1%e5%bc%8f/feed/" rel="self" type="application/rss+xml" />
	<link>https://vki.cc/tag/设计模式/</link>
	<description>白露的博客</description>
	<lastBuildDate>Thu, 22 Apr 2021 08:01:37 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>

<image>
	<url>https://cdn.vki.cc/wp-content/uploads/2018/03/cropped-icemaplen-1-32x32.png</url>
	<title>设计模式 归档 - 初晴神社</title>
	<link>https://vki.cc/tag/设计模式/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>【设计模式】05 &#8211; 模板方法模式</title>
		<link>https://vki.cc/greattruth/experience/599/</link>
					<comments>https://vki.cc/greattruth/experience/599/#respond</comments>
		
		<dc:creator><![CDATA[白露]]></dc:creator>
		<pubDate>Thu, 30 Aug 2018 07:45:12 +0000</pubDate>
				<category><![CDATA[咸鱼心得]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[心得]]></category>
		<category><![CDATA[设计模式]]></category>
		<guid isPermaLink="false">http://www.icemaplen.com/?p=599</guid>

					<description><![CDATA[<p>在一个操作方法中定义算法的流程，某些步骤由子类完成。模板方法模式让子类在不变更原有算法流程的情况下，还能重新定义其中的步骤。 举个栗子，现在巧克力和香子兰两个人肚子饿了，要吃饭。吃饭的过程有三&#8230;</p>
<p><a href="https://vki.cc/greattruth/experience/599/">【设计模式】05 &#8211; 模板方法模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<pre class="wp-block-preformatted">在一个操作方法中定义算法的流程，某些步骤由子类完成。模板方法模式让子类在不变更原有算法流程的情况下，还能重新定义其中的步骤。</pre>



<p class="has-black-color has-text-color wp-block-paragraph">举个栗子，现在巧克力和香子兰两个人肚子饿了，要吃饭。吃饭的过程有三个步骤：</p>



<p class="has-black-color has-text-color wp-block-paragraph">1.吃配菜；</p>



<p class="has-black-color has-text-color wp-block-paragraph">2.吃主食；</p>



<p class="has-black-color has-text-color wp-block-paragraph">3.喝饮料；</p>



<p class="has-black-color has-text-color wp-block-paragraph">虽然吃饭步骤一样，可是两个人吃的东西却不同。巧克力配菜要吃西红柿炒鸡蛋，主食要吃馒头，饮料要喝可乐；而香子兰要吃麻婆豆腐，米饭和牛奶。</p>



<p class="has-black-color has-text-color wp-block-paragraph">如果用程序表示的话，可以看出二者使用相同的验算流程，且实现的内容不一样。一般情况下我们会分别给二者写一套代码，这样做没有什么问题。可是如果后续开发需要添加新的功能呢，比如说红豆，时雨也要吃饭饭。或者她们想改变下吃饭的流程，先吃主食再吃配菜呢？是不是要为每套代码做出修改？显而易见这样的实现不太好，那么有没有一种好的实现方法呢？</p>



<p class="has-black-color has-text-color wp-block-paragraph">答案就是使用<strong>模板方法模式（Template）</strong></p>



<p class="has-black-color has-text-color wp-block-paragraph"><em><span style="color: #808080;">偷来的结构图_(:з」∠)_</span></em></p>



<div class="wp-block-image"><figure class="aligncenter"><a href="https://cdn.vki.cc/wp-content/uploads/2018/08/944365-5c903d791a9d001f.png" target="_blank" rel="noopener"><img  fetchpriority="high"  decoding="async"  width="500"  height="480"  src="https://cdn.vki.cc/wp-content/uploads/2018/08/944365-5c903d791a9d001f.png"  alt=""  class="wp-image-602"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/08/944365-5c903d791a9d001f.png 500w, https://cdn.vki.cc/wp-content/uploads/2018/08/944365-5c903d791a9d001f-300x288.png 300w"  sizes="(max-width: 500px) 100vw, 500px" ></a></figure></div>



<p class="wp-block-paragraph"><strong>1.定义一个算法的流程，即是很明确的定义算法的每一个步骤，并写在父类的方法中，而每一个步骤都可以是一个方法的调用。</strong></p>



<p class="wp-block-paragraph"><strong>2.某些步骤由子类完成。</strong></p>



<h2 id="%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0" class="wp-block-heading">代码实现</h2>



<h3 id="%e7%ae%97%e6%b3%95%e5%ae%9a%e4%b9%89%e7%b1%bb%ef%bc%9a" class="wp-block-heading">算法定义类：</h3>



<p class="wp-block-paragraph">由一个主方法和三个步骤方法组成，主方法不可重写，步骤方法必须在子类实现：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">abstract class IEat
{
    public void Eat()
    {
        EatDishes();
        EatStaple();
        Drink();
    }

    protected abstract void EatDishes();
    protected abstract void EatStaple();
    protected abstract void Drink();
}</pre>



<h3 id="%e7%ae%97%e6%b3%95%e6%ad%a5%e9%aa%a4%e7%9a%84%e5%ae%9e%e7%8e%b0%e7%b1%bb%ef%bc%9a" class="wp-block-heading">算法步骤的实现类：</h3>



<p class="wp-block-paragraph">巧克力：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class ChocolatEat : IEat
{
    protected override void EatDishes()
    {
        Console.WriteLine("配菜：西红柿炒鸡蛋");
    }

    protected override void EatStaple()
    {
        Console.WriteLine("主食：馒头");
    }
    protected override void Drink()
    {
        Console.WriteLine("饮料：可乐");
    }
}</pre>



<p class="wp-block-paragraph">香子兰：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class VinillaEat : IEat
{
    protected override void EatDishes()
    {
        Console.WriteLine("配菜：麻婆豆腐");
    }

    protected override void EatStaple()
    {
        Console.WriteLine("主食：米饭");
    }
    protected override void Drink()
    {
        Console.WriteLine("饮料：牛奶");
    }
}</pre>



<p class="wp-block-paragraph">在Main中调用：</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">static void Main(string[] args)
{
    ChocolatEat chocolat = new ChocolatEat();
    VinillaEat vinilla = new VinillaEat();

    Console.WriteLine("巧克力吃了：");
    chocolat.Eat();

    Console.WriteLine("-------------");
    Console.WriteLine("香子兰吃了：");
    vinilla.Eat();
}</pre>



<p class="wp-block-paragraph">结果：</p>



<div class="wp-block-image"><figure class="aligncenter"><img  decoding="async"  width="318"  height="218"  src="https://cdn.vki.cc/wp-content/uploads/2018/08/20180830154449.png"  alt=""  class="wp-image-603"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/08/20180830154449.png 318w, https://cdn.vki.cc/wp-content/uploads/2018/08/20180830154449-300x206.png 300w"  sizes="(max-width: 318px) 100vw, 318px" ></figure></div>



<h2 id="%e7%bb%93%e8%ae%ba" class="wp-block-heading">结论</h2>



<p class="has-black-color has-text-color wp-block-paragraph">模板方法模式将可能出现重复的“算法流程”从子类提升到父类中，减少重复的发生，并且也开放子类参与算法中各个步骤的执行或优化。但如果“算法流程”开放太多的步骤，并要求子类必须全部重新实现的话，反而会造成实现的困难，也不容易维护。</p>
<p><a href="https://vki.cc/greattruth/experience/599/">【设计模式】05 &#8211; 模板方法模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vki.cc/greattruth/experience/599/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【设计模式】04 &#8211; 外观模式</title>
		<link>https://vki.cc/greattruth/experience/563/</link>
					<comments>https://vki.cc/greattruth/experience/563/#comments</comments>
		
		<dc:creator><![CDATA[白露]]></dc:creator>
		<pubDate>Fri, 10 Aug 2018 14:45:21 +0000</pubDate>
				<category><![CDATA[咸鱼心得]]></category>
		<category><![CDATA[心得]]></category>
		<category><![CDATA[设计模式]]></category>
		<guid isPermaLink="false">http://www.icemaplen.com/?p=563</guid>

					<description><![CDATA[<p>外观模式：为子系统定义一组统一的接口，这个高级的接口会让子系统更容易被使用。 外观模式有点黑箱的意思，即把内部细节封装起来，对外只有简单的接口方便调用。比如一台电视机内部有显像系统，声音系统，&#8230;</p>
<p><a href="https://vki.cc/greattruth/experience/563/">【设计模式】04 &#8211; 外观模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<pre class="wp-block-preformatted">外观模式：为子系统定义一组统一的接口，这个高级的接口会让子系统更容易被使用。</pre>



<p class="has-black-color has-text-color wp-block-paragraph">外观模式有点黑箱的意思，即把内部细节封装起来，对外只有简单的接口方便调用。比如一台电视机内部有显像系统，声音系统，电子系统等等，通过这些系统协调工作才组成了一台功能正常的电视机。而当我们想看电视时，并不用关系这些系统怎么配合，只需要接通电源，打开电视机就可以看了。</p>



<p class="has-black-color has-text-color wp-block-paragraph">所以，外观模式的重点在于，<strong>它能将系统内部的互动细节隐藏以来，并提供简单方便的接口，之后客户端只需要通过这个接口，就可以操作一个复杂系统并让他们顺利运行。</strong></p>



<p class="wp-block-paragraph">惯例盗张结构图_(:з」∠)_</p>



<div class="wp-block-image"><figure class="aligncenter"><a href="https://cdn.vki.cc/wp-content/uploads/2018/08/20170901204306468.png" target="_blank" rel="noopener"><img  decoding="async"  width="1433"  height="795"  src="https://cdn.vki.cc/wp-content/uploads/2018/08/20170901204306468.png"  alt=""  class="wp-image-566"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/08/20170901204306468.png 1433w, https://cdn.vki.cc/wp-content/uploads/2018/08/20170901204306468-300x166.png 300w, https://cdn.vki.cc/wp-content/uploads/2018/08/20170901204306468-768x426.png 768w, https://cdn.vki.cc/wp-content/uploads/2018/08/20170901204306468-1024x568.png 1024w, https://cdn.vki.cc/wp-content/uploads/2018/08/20170901204306468-750x416.png 750w"  sizes="(max-width: 1433px) 100vw, 1433px" ></a></figure></div>



<blockquote><p>上图是使用外观模式之后的，如果未使用状态模式大概长这样：</p><figure><img  loading="lazy"  decoding="async"  class="aligncenter size-full wp-image-567"  src="https://cdn.vki.cc/wp-content/uploads/2018/08/20180810225336.png"  alt=""  width="602"  height="251"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/08/20180810225336.png 602w, https://cdn.vki.cc/wp-content/uploads/2018/08/20180810225336-300x125.png 300w"  sizes="auto, (max-width: 602px) 100vw, 602px" ></figure><p>看起来貌似也没多大问题，不过当Client多了可就不一样了：</p><figure><img  loading="lazy"  decoding="async"  class="aligncenter size-full wp-image-569"  src="https://cdn.vki.cc/wp-content/uploads/2018/08/20180810225617.png"  alt=""  width="663"  height="427"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/08/20180810225617.png 663w, https://cdn.vki.cc/wp-content/uploads/2018/08/20180810225617-300x193.png 300w"  sizes="auto, (max-width: 663px) 100vw, 663px" ></figure><p>这下调用结果相当混乱，很容易就晕了。。</p></blockquote>



<p class="has-black-color has-text-color wp-block-paragraph">可以看到整个系统分为三个部分：</p>



<ul class="has-luminous-vivid-orange-color has-text-color wp-block-list"><li>客户端，用户。从原本需要操作多个子系统的情况，改为只需要面对一个整合后的界面。</li><li>统一对外的界面。整合所有子系统的接口及功能，并提供接口供Client使用。&lt;br>同时接收客户端的信息后，将信息传送给子系统。</li><li>子系统。原本会由不同的Client来操作，改为只会由内部系统互相使用。</li></ul>



<h2 id="%e4%bb%a3%e7%a0%81%e6%bc%94%e7%a4%ba" class="wp-block-heading">代码演示</h2>



<h3 id="sussystem" class="wp-block-heading">SusSystem</h3>



<p class="has-black-color has-text-color wp-block-paragraph">为了方便演示每个系统都只有启动和关闭方法</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class SubSystem1
{
    public void Start()
    {
        Console.WriteLine("SubSystem1已启动");
    }

    public void Close()
    {
        Console.WriteLine("SubSystem1已关闭");
    }
}

class SubSystem2
{
    public void Start()
    {
        Console.WriteLine("SubSystem2已启动");
    }

    public void Close()
    {
        Console.WriteLine("SubSystem2已关闭");
    }
}

class SubSystem3
{
    public void Start()
    {
        Console.WriteLine("SubSystem3已启动");
    }

    public void Close()
    {
        Console.WriteLine("SubSystem3已关闭");
    }
}</pre>



<h3 id="facade" class="wp-block-heading">Facade</h3>



<p class="has-black-color has-text-color wp-block-paragraph">Facade持有了以上单个子系统的引用，并定义了总开关方法</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Facade
{
    private SubSystem1 sub1;
    private SubSystem2 sub2;
    private SubSystem3 sub3;

    public Facade()
    {
        sub1 = new SubSystem1();
        sub2 = new SubSystem2();
        sub3 = new SubSystem3();
    }

    public void StartAllSubSystem()
    {
        sub1.Start();
        sub2.Start();
        sub3.Start();
    }

    public void CloseAllSubSystem()
    {
        sub1.Close();
        sub2.Close();
        sub3.Close();
    }
}</pre>



<h3 id="client" class="wp-block-heading">Client</h3>



<p class="has-black-color has-text-color wp-block-paragraph">这里我们将Main方法当做Client，只需要一条命令就可以实现打开或关闭所有子系统的方法。</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">static void Main(string[] args)
{
    Facade facade = new Facade();
    facade.StartAllSubSystem();
    Console.WriteLine();
    facade.CloseAllSubSystem();
}</pre>



<h3 id="%e8%bf%90%e8%a1%8c%e7%bb%93%e6%9e%9c%ef%bc%9a" class="wp-block-heading">运行结果：</h3>



<div class="wp-block-image"><figure class="aligncenter"><img  loading="lazy"  decoding="async"  width="231"  height="164"  src="https://cdn.vki.cc/wp-content/uploads/2018/08/20180810232529.png"  alt=""  class="wp-image-570" ></figure></div>



<h2 id="%e4%bd%bf%e7%94%a8%e5%a4%96%e8%a7%82%e6%a8%a1%e5%bc%8f%e7%9a%84%e4%bc%98%e7%bc%ba%e7%82%b9" class="wp-block-heading">使用外观模式的优缺点</h2>



<p class="has-black-color has-text-color wp-block-paragraph">将复杂的子系统沟通交给单一的一个类负责，并提供单一界面给客户端使用，使客户端减少对系统的耦合度。</p>



<p class="has-black-color has-text-color wp-block-paragraph">使用状态模式可以将Client类单一化，方便的调用一个接口，而不必关心这个接口功能背后是一堆子系统怎么实现的。</p>



<p class="has-black-color has-text-color wp-block-paragraph">减少了Client类不必要的类引用及功能整合（只需要引用一个Facade就够了），增加了Client类被复用的机会。</p>



<p class="has-black-color has-text-color wp-block-paragraph">由此可见，外观模式很利于分工开发。在分工配合时，开发者只需要了解对方负责系统的Facade接口类，不必更进一步关心对方的实现方式。</p>



<p class="has-black-color has-text-color wp-block-paragraph">缺点即是由于将所有子系统集中在Facade接口中，最终会导致Facade接口类过于庞大和难以维护。</p>



<p class="has-black-color has-text-color wp-block-paragraph">这种情况下可以重构Facade接口类，将功能相近的子系统进行整合，以减少内部系统的依赖性，或是整合其他设计模式来减少接口类大小。</p>
<p><a href="https://vki.cc/greattruth/experience/563/">【设计模式】04 &#8211; 外观模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vki.cc/greattruth/experience/563/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>【设计模式】03 &#8211; 状态模式</title>
		<link>https://vki.cc/greattruth/experience/558/</link>
					<comments>https://vki.cc/greattruth/experience/558/#respond</comments>
		
		<dc:creator><![CDATA[白露]]></dc:creator>
		<pubDate>Thu, 09 Aug 2018 13:54:36 +0000</pubDate>
				<category><![CDATA[咸鱼心得]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[心得]]></category>
		<category><![CDATA[设计模式]]></category>
		<guid isPermaLink="false">http://www.icemaplen.com/?p=558</guid>

					<description><![CDATA[<p>[info]状态模式：让一个对象的行为随着内部状态的变化而变化，而该对象也像是换了类一样。[/info] 状态模式，顾名思义，在于状态以及切换。比较常用的就是状态机，一个游戏角色在空闲，移动，攻击等状态相互&#8230;</p>
<p><a href="https://vki.cc/greattruth/experience/558/">【设计模式】03 &#8211; 状态模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></description>
										<content:encoded><![CDATA[<p>[info]状态模式：让一个对象的行为随着内部状态的变化而变化，而该对象也像是换了类一样。[/info]</p>
<p>状态模式，顾名思义，在于状态以及切换。比较常用的就是状态机，一个游戏角色在空闲，移动，攻击等状态相互切换时，就可以用状态模式。从一种行为转化为另一种行为的过程都在游戏内部实现，玩家不需要理解这个转化过程。而且无论怎么转化，玩家都是控制的该角色，并不会因为其内部的转变而有所差异。</p>
<p>另外虽然游戏角色会从空闲切换到攻击等状态，它的“表现行为”会有所变化，但是对于客户端来说，并不会因为这样的变化，而改变对它的“操作方法”的方式，也就是从开发角度说，这个对象对外界的对应方式不会有任何改变。但是对象的内部确实是会通过“更换状态类对象”的方式来进行状态的转换。</p>
<h2 id="%e6%9d%a5%e7%9c%8b%e4%b8%8b%e7%8a%b6%e6%80%81%e6%a8%a1%e5%bc%8f%e7%9a%84%e7%bb%93%e6%9e%84%e5%9b%be%ef%bc%9a">来看下状态模式的结构图：</h2>
<p><span style="color: #808080;">（懒得画图了，自己找了个。与后续代码有些不同，不过整体结构是一样的）</span></p>
<p><a href="https://cdn.vki.cc/wp-content/uploads/2018/08/state_pattern_uml_diagram_1.png" target="_blank" rel="noopener"><img  loading="lazy"  decoding="async"  class="aligncenter wp-image-561 size-full"  src="https://cdn.vki.cc/wp-content/uploads/2018/08/state_pattern_uml_diagram_1.png"  alt=""  width="560"  height="387"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/08/state_pattern_uml_diagram_1.png 560w, https://cdn.vki.cc/wp-content/uploads/2018/08/state_pattern_uml_diagram_1-300x207.png 300w"  sizes="auto, (max-width: 560px) 100vw, 560px" ></a></p>
<p>其中：</p>
<p>[successbox title=&#8221;Context&#8221;]<strong>状态的拥有者</strong>，可以制定相关的接口，让外界能够得知状态的改变或通过操作让状态改变。[/successbox]</p>
<p>[infobox title=&#8221;State&#8221;]<strong>状态接口类</strong>，规范Context在特定状态下要表现的行为。[/infobox]</p>
<p>[infobox title=&#8221;StartState等&#8221;]<strong>具体状态类</strong>，实现Context在特定状态下该有的行为。比如角色空闲状态，攻击状态等。[/infobox]</p>
<h2 id="%e4%bb%a3%e7%a0%81%e5%ae%9e%e7%8e%b0">代码实现</h2>
<p>Context：</p>
<pre class="pure-highlightjs"><code class="cs">class Context
{
    private IState state;  // 代表当前状态

    // 更改状态
    public void SetState(IState state)
    {
        this.state = state;
    }

    // 状态行为
    public void Run()
    {
        if (state != null)
        {

            state.Handle();
        }
    }
}</code></pre>
<p>IState</p>
<p>抽象类，通过构造方法传入Context，以便后续操作中使用。并定义了一个抽象方法，使其在子类中实现。</p>
<pre class="pure-highlightjs"><code class="cs">abstract class IState
{
    protected Context context;

    public IState(Context context)
    {
        this.context = context;
    }

    public abstract void Handle();
}</code></pre>
<p>3个State</p>
<pre class="pure-highlightjs"><code class="cs">class StateA : IState
{
    public StateA(Context context) : base(context)
    {

    }

    public override void Handle()
    {
        Console.WriteLine("已切换到StateA");
        context.SetState(new StateB(context));
    }
}

class StateB : IState
{
    public StateB(Context context) : base(context)
    {

    }

    public override void Handle()
    {
        Console.WriteLine("已切换到StateB");
        context.SetState(new StateC(context));
    }
}

class StateC : IState
{
    public StateC(Context context) : base(context)
    {

    }

    public override void Handle()
    {
        Console.WriteLine("已切换到StateC");
        context.SetState(new StateA(context));
    }
}</code></pre>
<p>上述三个子类都实现了父类的抽象方法，用来表示在各自状态下的行为。这里为了演示，只做了最简单的切换状态功能。</p>
<p>Context类中提供了SetState方法用来让外界切换状态，而这个“外界”也可以是另一个State。所以实现上，状态的切换可以有一下两种方式：</p>
<ul>
<li>交由Context类本身，按条件在各状态之间切换；</li>
<li>产生Context类对象时，马上指定初始状态给Context对象，而后在后续执行过程中的状态转换则交由State对象负责，Context对象不再介入。</li>
</ul>
<p>测试代码：</p>
<pre class="pure-highlightjs"><code class="cs">static void Main(string[] args)
{
    Context context = new Context();
    context.SetState(new StateA(context));

    context.Run();
    context.Run();
    context.Run();
    context.Run();
}</code></pre>
<p>结果如下：</p>
<p><img  loading="lazy"  decoding="async"  class="aligncenter size-full wp-image-562"  src="https://cdn.vki.cc/wp-content/uploads/2018/08/20180809215559.png"  alt=""  width="243"  height="135" ></p>
<h2 id="%e7%bb%93%e8%ae%ba">结论</h2>
<p>使用状态模式的优点：</p>
<p><strong>1.减少错误的发生并降低维护难度；</strong></p>
<p>不再使用switch来判断状态，在后续更新维护时如果需要新的功能（状态），直接从IState派生就可以了，符合了开闭原则。</p>
<p><strong>2.状态执行环境单一化；</strong></p>
<p>与每一个状态有关的对象及操作都被实现在一个场景状态下，符合单一职责原则。</p>
<p>3.项目之间可以共享，增强可复用性。</p>
<hr />
<p><span style="color: #808080;">参考资料：《设计模式与游戏完美开发》</span></p>
<p><a href="https://vki.cc/greattruth/experience/558/">【设计模式】03 &#8211; 状态模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vki.cc/greattruth/experience/558/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【设计模式】02 &#8211; 中介者模式</title>
		<link>https://vki.cc/greattruth/experience/546/</link>
					<comments>https://vki.cc/greattruth/experience/546/#respond</comments>
		
		<dc:creator><![CDATA[白露]]></dc:creator>
		<pubDate>Wed, 25 Jul 2018 14:11:15 +0000</pubDate>
				<category><![CDATA[咸鱼心得]]></category>
		<category><![CDATA[心得]]></category>
		<category><![CDATA[设计模式]]></category>
		<guid isPermaLink="false">http://www.icemaplen.com/?p=546</guid>

					<description><![CDATA[<p>[info]中介者模式：用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用，从而使其耦合松散，而且可以独立地改变他们之间的交互。[/info] 中介者模式又叫做调停者模式，顾名思义跟房&#8230;</p>
<p><a href="https://vki.cc/greattruth/experience/546/">【设计模式】02 &#8211; 中介者模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></description>
										<content:encoded><![CDATA[<p>[info]中介者模式：用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用，从而使其耦合松散，而且可以独立地改变他们之间的交互。[/info]</p>
<p>中介者模式又叫做调停者模式，顾名思义跟房产中介是类似的。拿房产中介来说，现在房子买家和房子卖家非常多，如果任由房子买家和房子卖家自由交易，则会导致不同的买家和卖家之间有很多交互，一个买家会和多个卖家进行交涉，同样的一个卖家也会和多个买家进行交涉。如果在买房的过程中出现纠纷问题，则很难进行解决。就如下图所示一样。</p>
<p><img  loading="lazy"  decoding="async"  class="aligncenter wp-image-549 size-full"  src="https://cdn.vki.cc/wp-content/uploads/2018/07/20180725220617.png"  alt=""  width="312"  height="350"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/07/20180725220617.png 312w, https://cdn.vki.cc/wp-content/uploads/2018/07/20180725220617-267x300.png 267w"  sizes="auto, (max-width: 312px) 100vw, 312px" ></p>
<p>可以看出不同买家和卖家进行了很多错综复杂的交互，不利于发展。</p>
<ul>
<li>单一系统引入太多其他系统的功能，不利于单一系统的转换和维护；</li>
<li>单一系统被过多的系统所依赖，不利于接口的更改，容易牵一发动全身；</li>
<li>因为需提供给其他系统操作，系统的接口可能会过于庞大，不容易维护；</li>
</ul>
<p><strong>迪米特原则，尽量减少对象之间的交互，如果两个对象之间不必彼此直接通信，那么这两个对象就不应当发生任何直接的相互作用，如果其中的一个对象需要调用另一个对象的某一个方法的话，可以通过第三者转发这个调用。</strong></p>
<p>迪米特原则同样适用于本场景，我们可以引入第三者也就是中介。它的出现不需要买家和卖家进行直接交涉，而是通过中介而进行交涉。并且也不容易出现买卖家之间纠纷，因为有中介者房产中介进行第三方监督。如下图所示：</p>
<p><img  loading="lazy"  decoding="async"  class="aligncenter wp-image-550 size-full"  src="https://cdn.vki.cc/wp-content/uploads/2018/07/20180725220739.png"  alt=""  width="395"  height="357"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/07/20180725220739.png 395w, https://cdn.vki.cc/wp-content/uploads/2018/07/20180725220739-300x271.png 300w"  sizes="auto, (max-width: 395px) 100vw, 395px" ></p>
<p>可以看到图中的关系清晰了很多。</p>
<p>同理在软件开发中，如果为了减少对象之间的交互和耦合，符合迪米特原则，那么就可以使用中介者模式。</p>
<p><a href="https://vki.cc/greattruth/experience/546/">【设计模式】02 &#8211; 中介者模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vki.cc/greattruth/experience/546/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【设计模式】01 &#8211; 单例模式</title>
		<link>https://vki.cc/greattruth/experience/538/</link>
					<comments>https://vki.cc/greattruth/experience/538/#comments</comments>
		
		<dc:creator><![CDATA[白露]]></dc:creator>
		<pubDate>Sat, 14 Jul 2018 07:20:10 +0000</pubDate>
				<category><![CDATA[咸鱼心得]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[教程]]></category>
		<category><![CDATA[设计模式]]></category>
		<guid isPermaLink="false">http://www.icemaplen.com/?p=538</guid>

					<description><![CDATA[<p>[info]单例模式：是一种常用的软件设计模式，在它的核心结构中值包含一个被称为单例的特殊类。一个类只有一个实例，即一个类只有一个对象实例。[/info] 显然单例模式的要点有三个； 某个类只能有一个实例； &#8230;</p>
<p><a href="https://vki.cc/greattruth/experience/538/">【设计模式】01 &#8211; 单例模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></description>
										<content:encoded><![CDATA[<p>[info]<strong>单例模式：</strong>是一种常用的软件设计模式，在它的核心结构中值包含一个被称为单例的特殊类。一个类只有一个实例，即一个类只有一个对象实例。[/info]</p>
<div class="para"><span style="color: #000000;">显然单例模式的要点有三个；</span></div>
<ul>
<li class="para"><span style="color: #000000;">某个类只能有一个实例；</span></li>
<li class="para"><span style="color: #000000;">它必须自行创建这个实例；</span></li>
<li class="para"><span style="color: #000000;">它必须自行向整个系统提供这个实例。</span></li>
</ul>
<div class="para"><span style="color: #000000;">从具体实现角度来说，就是以下三点：</span></div>
<ul>
<li class="para"><span style="color: #000000;">单例模式的类只提供私有的构造函数，</span></li>
<li class="para"><span style="color: #000000;">类定义中含有一个该类的静态私有对象，</span></li>
<li class="para"><span style="color: #000000;">该类提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。</span></li>
</ul>
<h2 id="%e4%bc%98%e7%bc%ba%e7%82%b9" class="title-text">优缺点</h2>
<div class="para-title level-3">
<h3 id="%e4%bc%98%e7%82%b9" class="title-text"><span style="color: #000000;">优点</span></h3>
</div>
<div class="para"><span style="color: #000000;"><b>一、实例控制</b></span></div>
<div class="para"><span style="color: #000000;">单例模式会阻止其他对象实例化其自己的单例对象的副本，从而确保所有对象都访问唯一实例。</span></div>
<div class="para"><span style="color: #000000;"><b>二、灵活性</b></span></div>
<div class="para"><span style="color: #000000;">因为类控制了实例化过程，所以类可以灵活更改实例化过程。</span></div>
<div class="para-title level-3">
<h3 id="%e7%bc%ba%e7%82%b9" class="title-text"><span style="color: #000000;">缺点</span></h3>
</div>
<div class="para"><span style="color: #000000;"><b>一、开销</b></span></div>
<div class="para"><span style="color: #000000;">虽然数量很少，但如果每次对象请求引用时都要检查是否存在类的实例，将仍然需要一些开销。可以通过使用静态初始化解决此问题。</span></div>
<div class="para"><span style="color: #000000;"><b>二、可能的开发混淆</b></span></div>
<div class="para"><span style="color: #000000;">使用单例对象（尤其在类库中定义的对象）时，开发人员必须记住自己不能使用<b>new</b>关键字实例化对象。因为可能无法访问库源代码，因此应用程序开发人员可能会意外发现自己无法直接实例化此类。</span></div>
<div class="para"><span style="color: #000000;"><b>三、对象生存期</b></span></div>
<div class="para"><span style="color: #000000;">不能解决删除单个对象的问题。在提供内存管理的语言中（例如基于.NET Framework的语言），只有单例类能够导致实例被取消分配，因为它包含对该实例的私有引用。在某些语言中（如 C++），其他类可以删除对象实例，但这样会导致单例类中出现悬浮引用。。</span></div>
<h2 id="%e5%86%99%e6%b3%951%ef%bc%88%e5%8f%aa%e9%80%82%e7%94%a8%e4%ba%8e%e5%8d%95%e7%ba%bf%e7%a8%8b%e7%8e%af%e5%a2%83%ef%bc%89">写法1（只适用于单线程环境）</h2>
<p>由于单例模式只有一个实例，即没有继承，所以一般将其设为sealed。</p>
<p>同时把构造方法设为私有，防止从外部创建，我们可以定义一个静态的实例，在需要的时候创建该实例。</p>
<p>代码如下：</p>
<pre class="pure-highlightjs"><code class="cs">namespace _01_单例模式
{
    sealed class Singleton1
    {
        private static Singleton1 instance;
        private static Singleton1 Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Singleton1();
                }
                return instance;
            }
        }

        private Singleton1()
        {

        }
    }
}</code></pre>
<p>这种写法比较简单，只有在instance为空时才会创建实例，避免了重复创建。</p>
<p><strong>缺点：</strong>该代码在单线程下可以正常工作，但在多线程环境下可能会出现问题。如果存在两个线程同时运行到<code class="cs">if (instance == null)</code> 并且instance还未创建，那么两个线程都会创建一个实例，这样就不再满足单例模式要求了。</p>
<h2 id="%e5%86%99%e6%b3%952%ef%bc%88%e5%8f%af%e4%bb%a5%e5%9c%a8%e5%a4%9a%e7%ba%bf%e7%a8%8b%e4%b8%ad%e6%ad%a3%e5%b8%b8%e5%b7%a5%e4%bd%9c%ef%bc%89">写法2（可以在多线程中正常工作）</h2>
<p>为了解决写法1的缺点，需要加上一个同步锁。写法如下：</p>
<pre class="pure-highlightjs"><code class="cs">namespace _01_单例模式
{
    sealed class Singleton2
    {
        private static object syncObj = new object();

        private static Singleton2 instance;
        private static Singleton2 Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncObj)
                    {
                        if (instance == null)
                        {
                            instance = new Singleton2();
                        }
                    }
                }
                return instance;
            }
        }

        private Singleton2()
        {

        }
    }
}</code></pre>
<p>在这个类里面创建了一个object专门用与互斥锁判断，同时用了两个if语句。第一个语句限制只有在instance为空时进行互斥判断，提高了效率。</p>
<p>而第二个if，假如有两个线程同时运行到了<code class="cs">lock (syncObj)</code> ，其中一个线程向下执行，创建instance。创建之后另一个线程继续运行，如果没有第二个if，第二个线程还会创建instance，不符合要求。</p>
<p>该类解决了多线程的问题，不过运用了两个if，依然比较复杂。</p>
<h2 id="%e3%80%90%e6%8e%a8%e8%8d%90%e3%80%91%e5%86%99%e6%b3%953%ef%bc%88%e5%88%a9%e7%94%a8%e9%9d%99%e6%80%81%e6%9e%84%e9%80%a0%e6%96%b9%e6%b3%95%ef%bc%89">【推荐】写法3（利用静态构造方法）</h2>
<p>其实C#中又一个方法能够确保只调用一次，即静态构造方法。所以可以利用这个特点实现单例模式。</p>
<p>代码如下：</p>
<pre class="pure-highlightjs"><code class="cs">namespace _01_单例模式
{
    sealed class Singleton3
    {
        private static Singleton3 instance = new Singleton3();

        public static Singleton3 Instance
        {
            get
            {
                return instance;
            }
        }

        private Singleton3()
        {

        }
    }
}</code></pre>
<p>由于C#是在调用静态构造方法时初始化静态变量，在运行时能确保只调用一次静态构造方法，这样就能保证只初始化一次instance。</p>
<p>不过该方式依然有个小缺点：C#中的静态构造方法并非程序员控制，而是系统自动调用。假如Singleton3中有个静态方法，当我们第一次调用该静态方法时，instance就会被创建。但我们的本意希望调用Singleton3.Instance时创建。所以这个方式可能会过早的创建实例，降低内存使用效率。</p>
<h2 id="%e3%80%90%e6%8e%a8%e8%8d%90%e3%80%91%e5%86%99%e6%b3%954%ef%bc%88%e6%8c%89%e9%9c%80%e5%88%9b%e5%bb%ba%ef%bc%89">【推荐】写法4（按需创建）</h2>
<p>为了优化写法3，我们可以额外利用一个类。写法如下：</p>
<pre class="pure-highlightjs"><code class="cs">namespace _01_单例模式
{
    sealed class Singleton4
    {
        public static Singleton4 Instance
        {
            get
            {
                return Nested.instance;
            }
        }

        class Nested
        {
            internal static readonly Singleton4 instance = new Singleton4();

            static Nested()
            {

            }
        }

        private Singleton4()
        {

        }
    }
}</code></pre>
<p>在Singleton4内部定义了一个私有类型Nested，当我们第一次调用Singleton4.Instance时，会自动调用Nested的静态构造方法创建instance。如果不调用Singleton4.Instance，就不会触发.Net运行时调用Nested，也不会创建实例，这样就做到了按需创建。</p>
<p><a href="https://vki.cc/greattruth/experience/538/">【设计模式】01 &#8211; 单例模式</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vki.cc/greattruth/experience/538/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>【设计模式】学习笔记</title>
		<link>https://vki.cc/greattruth/experience/311/</link>
					<comments>https://vki.cc/greattruth/experience/311/#comments</comments>
		
		<dc:creator><![CDATA[白露]]></dc:creator>
		<pubDate>Mon, 22 Jan 2018 09:13:56 +0000</pubDate>
				<category><![CDATA[咸鱼心得]]></category>
		<category><![CDATA[心得]]></category>
		<category><![CDATA[教程]]></category>
		<category><![CDATA[设计模式]]></category>
		<category><![CDATA[转载]]></category>
		<guid isPermaLink="false">http://www.icemaplen.com/?p=311</guid>

					<description><![CDATA[<p>01 &#8211; 单例模式 02 &#8211; 中介者模式 03 &#8211; 状态模式 04 &#8211; 外观模式</p>
<p><a href="https://vki.cc/greattruth/experience/311/">【设计模式】学习笔记</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></description>
										<content:encoded><![CDATA[<p><a href="https://cdn.vki.cc/wp-content/uploads/2018/01/DesignModes.jpg" target="_blank" rel="noopener noreferrer"><img  loading="lazy"  decoding="async"  class="alignnone wp-image-314 size-full"  src="https://cdn.vki.cc/wp-content/uploads/2018/01/DesignModes.jpg"  alt=""  width="1587"  height="673"  srcset="https://cdn.vki.cc/wp-content/uploads/2018/01/DesignModes.jpg 1587w, https://cdn.vki.cc/wp-content/uploads/2018/01/DesignModes-300x127.jpg 300w, https://cdn.vki.cc/wp-content/uploads/2018/01/DesignModes-768x326.jpg 768w, https://cdn.vki.cc/wp-content/uploads/2018/01/DesignModes-1024x434.jpg 1024w, https://cdn.vki.cc/wp-content/uploads/2018/01/DesignModes-750x318.jpg 750w"  sizes="auto, (max-width: 1587px) 100vw, 1587px" ></a></p>
<p><span style="text-decoration: underline;"><strong><a href="https://vki.cc/greattruth/experience/538/" target="_blank" rel="noopener">01 &#8211; 单例模式</a></strong></span></p>
<p><span style="text-decoration: underline;"><strong><a href="https://vki.cc/greattruth/experience/546/" target="_blank" rel="noopener">02 &#8211; 中介者模式</a></strong></span></p>
<p><span style="text-decoration: underline;"><strong><a href="https://vki.cc/greattruth/experience/558/" target="_blank" rel="noopener">03 &#8211; 状态模式</a></strong></span></p>
<p><span style="text-decoration: underline;"><strong><a href="https://vki.cc/greattruth/experience/563/" target="_blank" rel="noopener">04 &#8211; 外观模式</a></strong></span></p>
<p><a href="https://vki.cc/greattruth/experience/311/">【设计模式】学习笔记</a>最先出现在<a href="https://vki.cc">初晴神社</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vki.cc/greattruth/experience/311/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
	</channel>
</rss>
