模式
来源:互联网 发布:跟明星做亲戚知乎 编辑:程序博客网 时间:2024/06/11 20:00
public abstract class PlotStrategy
{
public abstract void plot( float[] x, float[] y);
}
public class BarPlotStrategy :PlotStrategy
{
public override void plot(float[] xp, float[] yp) {
BarPlot bplot = new BarPlot ();
bplot.Show ();
bplot.plot (xp, yp);
}
Strategy 策略
意图
定义一系列的算法,把它们一个一个封装起来,并且使它们可相互替换。本模式使得算法可以独立于它的客户而变化。
场景
在开发程序的时候,我们经常会根据环境不同采取不同的算法对对象进行处理。比如,在一个新闻列表页面需要显示所有新闻,而在一个新闻搜索页面需要根据搜索关键词显示匹配的新闻。如果在新闻类内部有一个ShowData方法的话,那么我们可能会传入一个searchWord的参数,并且在方法内判断如果参数为空则显示所有新闻,如果参数不为空则进行搜索。如果还有分页的需求,那么还可能在方法内判断是否分页等等。
这样做有几个不好的地方,一是ShowData方法太复杂了,代码不容易维护并且可能会降低性能,二是如果还有其它需求的话势必就需要修改ShowData方法,三是不利于重用一些算法的共同部分。由此引入策略模式,把算法进行封装,使之可以灵活扩展和替换。
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace StrategyExample
{
class Program
{
static void Main(string[] args)
{
Data data = new Data();
data.Add("aaa");
data.Add("bbb");
data.Add("ccc");
data.Add("abc");
data.Show();
data.SetShowDataStrategy(new SearchData("a"));
data.Show();
data.SetShowDataStrategy(new ShowPagedData(2, 1));
data.Show();
}
}
abstract class ShowDataStrategy
{
abstract public void ShowData(IList data);
}
class ShowAllData : ShowDataStrategy
{
public override void ShowData(IList data)
{
for (int i = 0; i < data.Count; i++)
{
Console.WriteLine(data[i]);
}
}
}
class ShowPagedData : ShowDataStrategy
{
private int pageSize;
private int pageIndex;
public ShowPagedData(int pageSize, int pageIndex)
{
this.pageSize = pageSize;
this.pageIndex = pageIndex;
}
public override void ShowData(IList data)
{
for (int i = pageSize * pageIndex; i < pageSize * (pageIndex + 1); i++)
{
Console.WriteLine(data[i]);
}
}
}
class SearchData : ShowDataStrategy
{
private string searchWord;
public string SearchWord
{
get { return searchWord; }
set { searchWord = value; }
}
public SearchData(string searchWord)
{
this.searchWord = searchWord;
}
public override void ShowData(IList data)
{
for (int i = 0; i < data.Count; i++)
{
if (data[i].ToString().Contains(searchWord))
Console.WriteLine(data[i]);
}
}
}
class Data
{
private ShowDataStrategy strategy;
private IList data = new ArrayList();
public void SetShowDataStrategy(ShowDataStrategy strategy)
{
this.strategy = strategy;
}
public void Show()
{
if (strategy == null)
strategy = new ShowAllData();
Console.WriteLine(strategy.GetType().ToString());
strategy.ShowData(data);
}
public void Add(string name)
{
data.Add(name);
}
}
}
Template
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
场景
模版方法是非常容易理解的设计模式,一来是因为它没有过多结构上的交错,二来是因为这种代码复用技术对于掌握OO知识的人来说非常容易可以想到,很可能你已经在很多地方运用了模版方法。在运用一些设计模式的时候常常也会一起运用模版方法,甚至有的设计模式本身就带有模版方法的思想。
今天,我们给出这样一个实际的例子。做过银行支付、支付宝支付的人都知道,一个支付的过程是基于两个接口的。提交接口和网关返回接口,虽然各大网关的支付接口格式不同,比如有的网关对于支付金额的参数是money,有的网关又是amount,但是从支付的提交过程来说,我们一般都会经历以下步骤:
获取订单信息,验证订单的合法性
生成用于提交到各大网关的表单
记录日志
把表单提交到相应的网关
对于各个网关,生成的提交表单以及记录日志的方式是不一样的,但是整个支付流程以及流程中的获取订单信息、提交表单的过程是一样的。由此引入模版方法模式来复用不变的部分,把可变的部分留给子类去实现。
using System;
using System.Collections.Generic;
using System.Text;
namespace TemplateMethodExample
{
class Program
{
static void Main(string[] args)
{
PayGateway pg = new IPSGateway();
pg.SubmitOrder(new Order());
}
}
class Order
{
}
class SubmitForm
{
}
abstract class PayGateway
{
protected abstract void WriteLog(SubmitForm sf);
protected abstract SubmitForm GenerateOrderForm(Order order);
public void SubmitOrder(Order order)
{
if (order == null)
{
Console.WriteLine("Invalid Order");
return;
}
SubmitForm sf = GenerateOrderForm(order);
if (sf == null)
{
Console.WriteLine("Generate Submit Form Failed");
return;
}
WriteLog(sf);
}
}
class IPSGateway : PayGateway
{
protected override void WriteLog(SubmitForm sf)
{
Console.WriteLine("Log Wrote");
}
protected override SubmitForm GenerateOrderForm(Order order)
{
Console.WriteLine("Submit Form Generated");
return new SubmitForm();
}
}
}
代码说明
PayGateway类型是抽象模版角色。它定义了支付过程不变的部分,并且把变化部分定义为抽象操作,让子类去实现。其中的SubmitOrder方法是模版方法。
IPSGateway类型是具体模版角色。它代表了某一种支付网关,并且按照这种支付网关的接口标准来实现生成提交表单和记录日志的操作。
何时采用
如果某些类型的操作拥有共同的实现骨架和不同的实现细节的话,可以考虑使用模版方法来封装统一的部分。
实现要点
复用算法的骨架,将可变的实现细节留给子类实现。
留给子类实现的方法需要在父类中定义,可以是抽象方法也可以是带有默认实现的方法。
Facade
一个良好的面向对象应用程序应该是一个最小的类,这个类能够把其他可重用类的行为有效的组织起来。对一个子系统的类进行重构,直到每个类都有一个进行良好定义功能目标,所以代码易于维护。外观模式(Facade)的目的是提供一个接口,通过这个接口可以使一个子系统更容易使用。它(Facade)将客户的请求代理给适合的子系统对象。客户通过发送请求给(Facade)的方式与子系统通信。使用(Facade)的客户不需要直接访问子系统对象。 它对客户屏蔽了子系统组件,减少了客户处理的对象的数目。(1)
using System;
using System.Collections.Generic;
using System.Text;
namespace Facade
...{
/**//// <summary>
/// 子系统一,该子系统仅含有一个类
/// </summary>
public class DrawLine
...{
private int _point;
/**//// <summary>
/// 构造函数
/// </summary>
/// <param name="point">画线的数量</param>
public DrawLine(int point)
...{
this._point = point;
}
/**//// <summary>
/// 画下划线
/// </summary>
public void DrawUnderline()
...{
for (int i = 0; i < _point; i++)
...{
Console.WriteLine("_");
}
}
/**//// <summary>
/// 画中划线
/// </summary>
public void DrawMiddleline()
...{
for (int i = 0; i < _point; i++)
...{
Console.WriteLine("--");
}
}
}
/**//// <summary>
/// 子系统二,该子系统也仅含有一个类
/// </summary>
public class ShowData
...{
private string _defaultValue;
/**//// <summary>
/// 构造函数
/// </summary>
/// <param name="defaultValue">默认值</param>
public ShowData(string defaultValue)
...{
this._defaultValue = defaultValue;
}
/**//// <summary>
/// 显示详细的数据
/// </summary>
/// <param name="time">参数一</param>
/// <param name="outsideValue">参数二</param>
public void ShowParticularData(int time, string outsideValue)
...{
for (int i = 0; i < time; i++)
...{
Console.WriteLine(outsideValue);
Console.WriteLine("|");
}
Console.WriteLine(" ");
}
/**//// <summary>
/// 显示简单的数据
/// </summary>
/// <param name="outsideValue"></param>
public void ShowShortData(string outsideValue)
...{
Console.WriteLine(_defaultValue + ":" + outsideValue);
}
}
//使用外观模式,向外提供各个子系统的功能
public class Facade
...{
private int _times;
private string _defaultValue;
private DrawLine dl;
private ShowData sd;
public Facade(int times, string defaultValue)
...{
_times = times;
_defaultValue = defaultValue;
dl = new DrawLine(_times);
sd = new ShowData(_defaultValue);
}
/**//// <summary>
/// 完成任务一:画下划线,显示详细的数据
/// </summary>
public void DrawPicture()
...{
dl.DrawUnderline();
sd.ShowParticularData(_times, _defaultValue);
}
/**//// <summary>
/// 完成任务二:画中划线,显示简单的数据
/// </summary>
public void DrawImage()
...{
dl.DrawMiddleline();
sd.ShowShortData(_defaultValue);
}
}
/**//// <summary>
/// 客户类
/// </summary>
public class Client
...{
private const int _times = 10;
private const string _defaultValue = "默认值";
static void Main(string[] args)
...{
//---------- 非使用Facade模式时,常见的用法--------------------
Console.WriteLine("非使用Facade模式时,常见的用法. ");
DrawLine dl = new DrawLine(_times);
ShowData sd = new ShowData(_defaultValue);
dl.DrawUnderline();
dl.DrawMiddleline();
sd.ShowParticularData(_times, _defaultValue);
sd.ShowShortData(_defaultValue);
//-------------------结束--------------------------------------
//---------- 使用Facade模式的用法--------------------
Console.WriteLine(" 使用Facade模式的用法. ");
Facade fc = new Facade(_times, _defaultValue);
fc.DrawPicture();
fc.DrawImage();
//-------------------结束--------------------------------------
}
}
}
客户程序与抽象类的实现部分之间存在很大的依赖性,引入Facade将这个子系统与客户以及其他的子系统的分析,可以提供子系统的独立性和可移植性。构建一个层次结构的子系统时使用定义子系统中每层的入口点。如果子系统之间是相互依赖,你可以让它们仅通过进行通信,从而简化了它们之间的依赖关系。(3)
客户程序与抽象类的实现部分之间存在很大的依赖性,引入Facade将这个子系统与客户以及其他的子系统的分析,可以提供子系统的独立性和可移植性。构建一个层次结构的子系统时使用定义子系统中每层的入口点。如果子系统之间是相互依赖,你可以让它们仅通过进行通信,从而简化了它们之间的依赖关系。(3)
抽象工厂
我们引入Abstract Factory,抽象工厂生产的都是实际类型的接口(或者抽象类型),如果加了新的场景可以确保不需要修改加载场景的那部分代码。
展
AbstractFactory factory = new McDFactory(); //选择去麦当劳吃
IHamburger hamburger = factory.CreateHamburger(); //选择吃汉堡
WEB 工厂创建一个属于类的工厂, 这个工厂是通过反射来动态获取的, 工厂实际上对应着数据处理层的一个类,工厂是抽像类和抽像方法,工厂里面的方法和数据处理层是一样的,当然这个类是工厂的抽像继承类,工厂里面可以通过静态方法自已创建一个工厂,通过
创建一个工厂也就得到了数据处理层的一个类的方法了, 他就可以直接使用他自已的方法,直接获取数据。
工厂这种取数据方式按我的理解是:你需要什么类,我就动态的取到什么类, 你需要什么方法,类里面包括了,
数据处理层通过赋值于实体类,给工厂(抽像类和抽像方法),再通过工厂放到界面上去。