简介:本教程供小白作入门使用,深入学习需要寻找完整的的《设计模式》教材。本教程一般包括理解部分,和标准化的回答部分。
目录:
1.设计模式介绍
1.1 理解设计模式
1.2 标准答案:什么是设计模式
2. 状态模式
2.1 理解状态模式
2.2 标准答案:什么是状态模式
2.3 状态模式的运用
3. 外观模式
3.1 理解外观模式
3.2 标准答案:什么是外观模式
3.3 外观模式的运用
4.工厂模式
4.1 理解工厂模式
4.1.1 理解简单工厂模式
4.1.2 理解工厂模式
4.1.3 理解抽象工厂模式
4.2 标准答案的回答工厂模式
4.2.1 标准答案:什么是简单工厂模式
4.2.2 标准答案:什么是工厂模式
4.2.3 标准答案:什么是抽象工厂模式
4.3 工厂模式的运用
4.3.1 简单工厂模式的运用
4.3.2 工厂模式的运用
4.3.3 抽象工厂的运用
5.命令模式
5.1 理解命令模式
5.2 标准答案:什么是命令模式
5.3 命令模式的运用
6.单例模式
6.1 理解单例模式
6.2 标准答案:什么是单例模式
6.3 单例模式的运用
7.观察者模式
7.1 理解观察者模式
7.2 标准答案:什么是观察者模式
7.3 观察者模式的运用
8.中介者模式
8.1 理解中介者模式
8.2 标准答案:什么是中介者模式
8.3 中介者模式的运用
1.1理解设计模式
简介:如果您也是新人,当您第一次查看一个程序框架的代码的时候,可能会发现“我擦这是个啥玩意?‘’ 并表示无从下手。
图1.1 Unity3D中的Strangioc框架目录
其实这些都是好多个设计模式,组合在一起就是个框架了,只有懂得了设计模式才能懂框架,就像是从加法才能再到乘法,这是没办法的事情。为啥要用设计模式?举例子,假如没有红绿灯,路上乱成一片还容易发生碰撞,一旦用了红绿灯的规则,立马就顺畅了。设计模式也是一种规则和规范,避免代码出现各种重大的失误,就像是红绿灯。设计模式是一种经验,框架也是经验,就是开发大程序的经验--曾经有人开发大型程序,模块与模块之间就像没有红路灯的马路一样,冲突成了那啥。痛定思痛,开发出个框架出来,模块间不冲突了,大家觉得不错,哎,就流行开来了,以后我的软件出这种冲突,我就套用这种框架。
1.2标准答案:什么是设计模式
每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动。
设计模式是为特定场景下的问题而定制的解决方案。
设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。
设计模式是对读者经常遇到的设计问题的可再现的解决方案(The Smalltalk Companion)。
Patterns,顾名思义,具有某种重复性规律的方案。Design Patterns,就是设计过程中可以反复使用的、可以解决特定问题的设计方法。
一般而言,一个模式有四个基本要素:
1. 模式名称(pattern name) 一个助记名,它用一两个词来描述模式的问题、解决方案和效果。
2. 问题(problem) 描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设计的类或对象结构。有时候,问题部分会包括使用模式必须满足的一系列先决条件。
3. 解决方案(solution) 描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。因为模式就像一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象组合)来解决这个问题。
4. 效果(consequences) 描述了模式应用的效果及使用模式应权衡的问题。尽管我们描述设计决策时,并不总提到模式效果,但它们对于评价设计选择和理解使用模式的代价及好处具有重要意义。软件效果大多关注对时间和空间的衡量,它们也表述了语言和实现问题。因为复用是面向对象设计的要素之一,所以模式效果包括它对系统的灵活性、扩充性或可移植性的影响,显式地列出这些效果对理解和评价这些模式很有帮助。
2.状态模式
2.1 理解状态模式
什么是状态模式?首先我们知道水有三种状态,气态的水蒸气,液态的水,固态的冰,他们可以通过加热和冷却互相转换,这是一个自然界的规律。
有一天,有一个游戏开发者叫小蜜蜂,想开发一款格斗的游戏,他设定在这个游戏里,主角被攻击了会暴怒喷火并提升攻击强度,暴怒一段时间后才会变正常,然后如果主角暴怒的时候被攻击,就会死亡。
作为一个小白开发者,他开始写代码:
If(Player.BeAttack()) //如果主角被攻击了
{
Player.Anger(); //暴怒喷火
}
……
然后开发者小蜜蜂发现主角一直在暴怒喷火,怎么也死不了,因为按照他写的代码只要被攻击了就会暴怒喷火,而他一直在被攻击,所以一直被触发暴怒喷火。于是开发者小蜜蜂大喊:普通状态下被攻击才暴怒,暴怒状态下被攻击了就死亡!这样,主角有了两种状态,普通状态,暴怒状态,每个状态都有不同的行为方式,面对攻击有不同的结果,而且能够互相转换,于是状态模式就诞生了,这种状态模式把模型分成了几种状态,不同的状态有不同的特性。而水是一种天然的状态模式,它三中状态,每种状态有不同的特性,他们都能互相转换:
图:水的“状态模式”模型图
2.2 标准答案:什么是状态模式
状态模式定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。状态模式是一种对象行为型模式。
状态模式的使用场景:
(1)对象的行为依赖于它的状态,并且可以在运行时根据状态改变行为。
(2)代码中包含大量与对象状态有关的if/else语句,这些条件对应于对象的各种状态,这些冗余条件语句的出现导致代码的可维护性和灵活性变差,这种情况适合使用状态模式进行优化。
状态模式角色介绍:
(1)Context类,定义客户端所感兴趣的接口,并且内部维护一个具体状态类的实例,从而维护了对象的现有状态。
(2)State:抽象状态类或状态接口,用以抽象封装行为。
(3)ConcreteState类:具体状态类,实现了State中的抽象方法。
2.3 状态模式的应用
2.3.1 实现基本方法
编译器Visual Studio 2017.项目结构图:(注意:在创建好工程的之后,对工程“解决方案‘’DesignModel”右键,再添加新建项目代码文件夹什么的,直接“文件/新建”容易出错)
Program.cs:
using System;
using DesignModel.Structural;
namespace DesignModel
{
class Program
{
static void Main(string[] args)
{
// Setup context in a state
Context c = new Context(new ConcreteStateA());
// Issue requests, which toggles state
c.Request();
c.Request();
c.Request();
c.Request();
Console.ReadLine();
}
}
}
Structural/State.cs:
namespace DesignModel.Structural
{
public abstract class State
{
public abstract void Handle(Context context);
}
}
Structural/Context.cs
using System;
namespace DesignModel.Structural
{
public class Context
{
private State _state;
public Context(State state)
{
this.State = state;
}
public State State
{
get
{
return _state;
}
set
{
_state = value;
Console.WriteLine("State: " + _state.GetType().Name);
}
}
public void Request()
{
_state.Handle(this);
}
}
}
Structural/ConcreteStateA.cs :
namespace DesignModel.Structural
{
public class ConcreteStateA : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateB();
}
}
}
Structural/ConcreteStateB.cs :
namespace DesignModel.Structural
{
public class ConcreteStateB : State
{
public override void Handle(Context context)
{
context.State = new ConcreteStateA();
}
}
}
运行结果:
工程源代码见地址:
2.3.2用代码实现水的状态变换
编译工具: Visual Studio 2017 项目结构:
Program.cs:
using StatePatternDemo.Structural;
using System;
namespace StatePatternDemo
{
class Program
{
static void Main(string[] args)
{
WaterContext water = new WaterContext(new LiquidState());
water.ColdRequest();
water.HotRequest();
water.HotRequest();
Console.ReadLine();
}
}
}
Structural/WaterContext.cs :
using System;
namespace StatePatternDemo.Structural
{
public class WaterContext
{
private State _state;
public WaterContext(State state)
{
this._state = state;
}
public State State
{
get
{
return _state;
}
set
{
_state = value;
Console.WriteLine("水的状态已经变为了: " + _state.GetType().Name);
}
}
public void HotRequest()
{
_state.HotHandle(this);
}
public void ColdRequest()
{
_state.ColdHandle(this);
}
}
}
Structural/State.cs:
namespace StatePatternDemo.Structural
{
public abstract class State
{
//热处理过程
public abstract void HotHandle(WaterContext context);
//冷处理过程
public abstract void ColdHandle(WaterContext context);
}
}
Structural/SolidState.cs: //固态状态
using System;
namespace StatePatternDemo.Structural
{
public class SolidState : State
{
public override void ColdHandle(WaterContext context)
{
Console.WriteLine("进行冷处理");
}
public override void HotHandle(WaterContext context)
{
Console.WriteLine("进行热处理");
context.State = new LiquidState();
}
}
}
Structural/LiquidState.cs: //液态状态
using System;
namespace StatePatternDemo.Structural
{
public class LiquidState : State
{
public override void ColdHandle(WaterContext context)
{
Console.WriteLine("进行冷处理");
context.State = new SolidState();
}
public override void HotHandle(WaterContext context)
{
Console.WriteLine("进行热处理");
context.State = new GasState();
}
}
}
Structural/GasState.cs: //气态状态
using System;
namespace StatePatternDemo.Structural
{
class GasState : State
{
public override void ColdHandle(WaterContext context)
{
Console.WriteLine("进行冷处理");
context.State = new LiquidState();
}
public override void HotHandle(WaterContext context)
{
Console.WriteLine("进行热处理");
}
}
}
运行结果:
项目的源代码:
3.外观模式
3.1 理解外观模式
假如现在有两台洗衣机摆在你的面前,第一台是老式的洗衣机,洗衣服的时候,你需要 :
- 先打开水阀
- 扭动定时扭
- 按下漂洗开关进行漂洗
- 漂洗完放入甩干桶
- 扭动定时扭
- 按下甩干开关进行甩干
第二台是一台全自动的洗衣机,它的操作过程是:
- 按下按钮,一键洗衣,然后啥也不用管了
请问您会选择哪一种,基本上是选择第二种一键洗衣的全自动洗衣机。虽然事实上,这两种洗衣机,他们的机械结构都是一样的,可是第二种全自动的洗衣机只是多出了一个更简单的按钮—一键洗衣,其实这个一键洗衣就隐约体现除了一种叫外观模式的思想,“隐藏系统的内部复杂性,向别人提供了一个简单粗暴的系统的接口”,又比如去医院看病,可能要去挂号、门诊、划价、取药,让患者或患者家属觉得很复杂,假如出了一个APP,可以一键问诊,自动把这些流程过完,然后直接看大夫。那么这个APP就是一个典型的外观模式看病APP。
3.2 标准答案:什么是外观模式
外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。
这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
简单来说,该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用。这个模式中,涉及到3个角色。
1).门面角色:外观模式的核心。它被客户角色调用,它熟悉子系统的功能。内部根据客户角色的需求预定了几种功能的组合。
2).子系统角色:实现了子系统的功能。它对客户角色和Facade时未知的。它内部可以有系统内的相互交互,也可以由供外界调用的接口。
3).客户角色:通过调用Facede来完成要实现的功能。
3.3 如何使用外观模式
3.3.1 最基本的外观模式结构:
项目结构图:
Structural/SubSystemOne.cs:
using System;
namespace FacadeModel.Stuctural
{
public class SubSystemOne
{
public void MethodOne()
{
Console.WriteLine(" SubSystemOne Method");
}
}
}
Structural/SubSystemTwo.cs:
using System;
namespace FacadeModel.Stuctural
{
public class SubSystemTwo
{
public void MethodTwo()
{
Console.WriteLine(" SubSystemTwo Method");
}
}
}
Structural/SubSystemThree.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FacadeModel.Stuctural
{
public class SubSystemThree
{
public void MethodThree()
{
Console.WriteLine(" SubSystemThree Method");
}
}
}
Structural/SubSystemFour.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FacadeModel.Stuctural
{
public class SubSystemFour
{
public void MethodFour()
{
Console.WriteLine(" SubSystemFour Method");
}
}
}
Structural/Facade.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FacadeModel.Stuctural
{
public class Facade
{
private SubSystemOne _one;
private SubSystemTwo _two;
private SubSystemThree _three;
private SubSystemFour _four;
public Facade()
{
_one = new SubSystemOne();
_two = new SubSystemTwo();
_three = new SubSystemThree();
_four = new SubSystemFour();
}
public void MethodA()
{
Console.WriteLine("\nMethodA() ---- ");
_one.MethodOne();
_two.MethodTwo();
_four.MethodFour();
}
public void MethodB()
{
Console.WriteLine("\nMethodB() ---- ");
_two.MethodTwo();
_three.MethodThree();
}
}
}
Program.cs:
using FacadeModel.Stuctural;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FacadeModel
{
class Program
{
static void Main(string[] args)
{
Facade facade = new Facade();
facade.MethodA();
facade.MethodB();
Console.ReadLine();
}
}
}
运行结果:
3.3.2 用外观模式实现一个洗衣机模型
编译工具:Visual Studio 2017 ,代码结构:
Structural/WaiteSubSystem.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FacadeModel.Stuctural
{
public class WaiteSubSystem
{
public void KeepWorkingForOneHour()
{
Console.WriteLine(" 定时子模块被调用:保持运行一个小时");
}
}
}
Structural/WashSubSystem.cs:
using System;
namespace FacadeModel.Stuctural
{
public class WashSubSystem
{
public void OpenWashMachine()
{
Console.WriteLine(" 滚筒子模块被调用:开启滚筒进行洗衣");
}
}
}
Structural/WaterSubSystem.cs:
using System;
namespace FacadeModel.Stuctural
{
public class WaterSubSystem
{
public void OpenWaterTap()
{
Console.WriteLine(" 水阀子模块被调用:开启水阀进行入水,直到注满");
}
}
}
Structural/AutoButtonFacade.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FacadeModel.Stuctural
{
public class AutoButtonFacade
{
private WaterSubSystem _water;
private WashSubSystem _wash;
private WaiteSubSystem _waite;
public AutoButtonFacade()
{
_water = new WaterSubSystem();
_wash = new WashSubSystem();
_waite = new WaiteSubSystem();
}
public void OnClickAutoButton()
{
Console.WriteLine("\n一键洗衣开始启动 ---- ");
_water.OpenWaterTap();
_wash.OpenWashMachine();
_waite.KeepWorkingForOneHour();
}
}
}
Program.cs:
using FacadeModel.Stuctural;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DesignModelDemo
{
class Program
{
static void Main(string[] args)
{
//外部的用户只需要操作这个接口进行洗衣服
AutoButtonFacade button = new AutoButtonFacade();
button.OnClickAutoButton();
Console.ReadLine();
}
}
}
外部只需要调用这个接口:
所得出的运行结果:
项目源代码:之后会整理贴出来