>> strategy(策略模式)
1. 概述
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们还可以互相替换。策略模式让算法独立于使用它的客户而独立变化
2. 适用性
1) 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。即一个系统需要动态地在几种算法中选择一种
2) 需要使用一个算法的不同变体。例如,你可能会定义一些反映不同的空间/时间权衡的算法。当这些变体实现为一个算法的类层次时,可以使用策略模式。
3) 算法使用客户不应该知道的数据。可以使用策略模式以避免暴露复杂的、与算法相关的数据结构。
4) 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现。将相关的条件分支移入它们各自的strategy类中以代替这些条件语句。
3. 结构
4. 实例
#region 封装 UseWeapon() 行为
/// <summary>
/// 定义使用 武器接口
/// </summary>
public interface IWeaponable
{
void UseWeapon();
}
// 使用 剑 的类
public class UseSword : IWeaponable
{
public void UseWeapon()
{
Console.WriteLine("Action: Sword Armed. There is a sharp sword in my hands now.");
}
}
// 使用 斧 的类
public class UseAxe : IWeaponable
{
public void UseWeapon()
{
Console.WriteLine("Action: Axe Armed. There is a heavy axe in my hands now.");
}
}
// 不能使用武器的类
public class UseNothing : IWeaponable
{
public void UseWeapon()
{
Console.WriteLine("Speak: I can't use any weapon.");
}
}
#endregion
#region 定义角色类
/// <summary>
/// 角色基类
/// </summary>
public abstract class Character
{
protected IWeaponable WeaponBehavior; // 通过此接口调用实际的 UseWeapon方法。
// 使用武器,通过接口来调用方法
public void UseWeapon()
{
WeaponBehavior.UseWeapon();
}
// 动态地给角色更换武器
public void ChangeWeapon(IWeaponable newWeapon)
{
Console.WriteLine("Haha, I've got a new equip.");
WeaponBehavior = newWeapon;
}
public void Walk()
{
Console.WriteLine("I'm start to walk ...");
}
public void Stop()
{
Console.WriteLine("I'm stopped.");
}
public abstract void DisplayInfo(); // 显示角色信息
}
// 定义野蛮人
public class Barbarian : Character
{
public Barbarian()
{
// 初始化继承自基类的WeaponBehavior变量
WeaponBehavior = new UseAxe(); // 野蛮人用斧
}
public override void DisplayInfo()
{
Console.WriteLine("Display: I'm a Barbarian from northeast.");
}
}
// 定义圣骑士
public class Paladin : Character
{
public Paladin()
{
WeaponBehavior = new UseSword();
}
public override void DisplayInfo()
{
Console.WriteLine("Display: I'm a paladin ready to sacrifice.");
}
}
// 定义法师
public class Wizard : Character
{
public Wizard()
{
WeaponBehavior = new UseNothing();
}
public override void DisplayInfo()
{
Console.WriteLine("Display: I'm a Wizard using powerful magic.");
}
}
#endregion
// 测试程序
class Program
{
static void Main(string[] args)
{
Character barbarian = new Barbarian(); // 默认情况下野蛮人用斧
barbarian.DisplayInfo();
barbarian.Walk();
barbarian.Stop();
barbarian.UseWeapon();
barbarian.ChangeWeapon(new UseSword()); // 现在也可以使用剑
barbarian.UseWeapon();
barbarian.ChangeWeapon(new UseNothing());// 也可以让他什么都用不了,当然一不会这样:
barbarian.UseWeapon();
Console.ReadKey();
}
}
>> memento(备忘录模式)
1. 概述
Memento模式也叫备忘录模式,它的作用是在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,在需要的时候(undo/rollback)恢复对象以前的状态
2. 适用性
必须保存一个对象在某一时刻(部分)状态,这样以后需要时它才能恢复到先前的状态。如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
3. 结构
4. 实例分析
public class OurObjectMemento
{
int internalState;
string anotherState;
public int InternalState
{
get
{
return internalState;
}
}
public string AnotherState
{
get
{
return anotherState;
}
}
public OurObjectMemento(int internalState, string anotherState)
{
this.internalState = internalState;
this.anotherState = anotherState;
}
}
public class OurObject
{
int internalState = 0;
string anotherState = "I know nothing";
public OurObjectMemento CreateMemento()
{
return new OurObjectMemento(internalState, anotherState);
}
public void ReStoreMemento(OurObjectMemento memento)
{
this.internalState = memento.InternalState;
this.anotherState = memento.AnotherState;
}
public void DoStuff()
{
internalState = 42;
anotherState = "I know the question too";
}
public void PrintState()
{
Console.WriteLine("current state is {0}:{1}", internalState, anotherState);
}
}
由上可知,memento自身公开了所有OurObject内部变量。在SharpDevelop中,所有memento都可将自身转换为XML(并可返回),从而保持了对象状态的连续性
>> proxy(代理模式)
1. 意图
为其他对象提供一种代理以控制这个对象的访问
2. 概述
在软件系统中,有些对象有时候由于跨越网络或者其它的障碍,而不能够或者不想直接访问另一个对象,如果直接访问会给系统带来不必要的复杂性,这时候可以在客户程序和目标对象之间增加一层中间层,让代理对象来代替目标对象打点一切。
3. 结构图
4. 实例分析
/// <summary>
/// 代理接口,保证client&server都实现相应方法
/// </summary>
public interface IMath
{
double Add(double x, double y);
double Sub(double x, double y);
double Mul(double x, double y);
double Dev(double x, double y);
}
/// <summary>
/// 服务器端方法
/// </summary>
public class Math : IMath
{
public double Add(double x, double y)
{
return x + y;
}
public double Sub(double x, double y)
{
return x - y;
}
public double Mul(double x, double y)
{
return x * y;
}
public double Dev(double x, double y)
{
return x / y;
}
}
/// <summary>
/// 代理方法
/// </summary>
public class MathProxy : IMath
{
Math math = new Math();
public double Add(double x, double y)
{
return math.Add(x, y);
}
public double Sub(double x, double y)
{
return math.Sub(x, y);
}
public double Mul(double x, double y)
{
return math.Mul(x, y);
}
public double Dev(double x, double y)
{
return math.Dev(x, y);
}
}
/// <summary>
/// 主程序
/// </summary>
public class App
{
public static void Main()
{
MathProxy proxy = new MathProxy();
double addresult = proxy.Add(2, 3);
double subresult = proxy.Sub(2, 3);
double mulresult = proxy.Mul(2, 3);
double devresult = proxy.Dev(2, 3);
}
}
分析:实例中无非在客户端和Math类之间增加了一个间接层,这也是我们比较常见的解决问题的手段之一。另外,对于程序中的接口Imath,并不是必须的,大多数情况下,我们为了保持对象操作的透明性,并强制实现类、代理类所要调用的所有的方法,我们会让他们实现同一个接口。