第四讲 设计模式
===================================================创建型设计模式==========================================================
一: 单利模式
二: -------------------------------------------------------------------简单工厂------------------------------------------------
概述:我们在实际开发中,需求是变化的,我们在使用的一个对象,并不能在编译期确定需要让类延时创建,
简单工厂: 解决的事"单一对象的创建"问题
三: ----------------------------------------------------------------抽象工厂-------------------------------------------
概述:在我们实际开发中,我们的需求中 "某一些对象"或者一组对象在变化,不能在编译器确定
抽象工厂 : 解析的是 "一组对象的创建"问题
抽象工厂:一般用接口实现, 少用继承
一组实现,也就是我们根据一组接口,做了不同的实现
抽象工厂:选择方法,也就是我们根据用户的需求或者配置,在不同的场合需要选择使用,可以用这种模式
案例:财务软件
2.1 抽象产品:一组接口。也就是我们要找到的存在变化的业务!
2.2 实体产品:一组实现。也就是我们根据一组接口,做了不同的实现。
2.3 抽象工厂:选择方法。也就是我们要根据用户的需求(配置)来返回一组接口的实现,给调用者。
在选择方法模块中,实际开发时,我们可能不会添加模块引用,因为这个可能是第三方完成的。
【3】应用场合:如果你发现相同的业务,有不同的实现,在不同的场合需要选择使用,就可以选择这个模式。
典型的:项目多数据库支持。财务软件算法的封装,游戏不同的场景设置...
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
IPrint.IPrintFace myif1 = PrintFactory.Class1.CreateFacroy();
Console.WriteLine("------------------工厂类输出--------------------------");
myif1.GetToInt(100);
myif1.ShowToString("");
Console.WriteLine("------------------工厂类输出<泛型>--------------------------");
IPrint.IPrintFace myfca = PrintFactory.Class1.CreateTFacroy<IPrint.IPrintFace>("Class1");
myfca.GetToInt(400);
myfca.ShowToString("");
Console.Read();
}
}
}
namespace IPrint
{
/// <summary>
/// 接口类
/// </summary>
public interface IPrintFace
{
int GetToInt(int parm);
void ShowToString(string parm);
}
}
namespace PrintFactory
{
/// <summary>
/// 工厂类
/// </summary>
public class Class1
{
/// <summary>
/// 配置加载那个接口实现
/// </summary>
private static string AppName = "PrintImpl1";
/// <summary>
/// 工厂创建 (这种还是不够灵活,类名称是写死的,应该使用泛型来做,达到更加的灵活)
/// </summary>
/// <returns></returns>
public static IPrint.IPrintFace CreateFacroy()
{
return (IPrint.IPrintFace)Assembly.Load(AppName).CreateInstance(AppName + ".Class1");
}
/// <summary>
/// 泛型的广场创建
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="className"></param>
/// <returns></returns>
public static T CreateTFacroy<T>(string className)
{
return (T)Assembly.Load(AppName).CreateInstance(AppName + "." + className);
}
}
}
namespace PrintImpl1
{
/// <summary>
/// 实现类1
/// </summary>
public class Class1:IPrint.IPrintFace
{
public int GetToInt(int parm)
{
Console.WriteLine("实现接口1中GetToInt数据");
return 100;
}
public void ShowToString(string parm)
{
Console.WriteLine("实现接口1中ShowToString数据");
}
}
}
namespace PringImpl2
{
/// <summary>
/// 实现类2
/// </summary>
public class Class1:IPrint.IPrintFace
{
public int GetToInt(int parm)
{
Console.WriteLine("实现接口2中GetToInt数据");
return 500;
}
public void ShowToString(string parm)
{
Console.WriteLine("实现接口2中ShowToString数据");
}
}
}
====================================================结构型设计模式=======================================================
一: ---------------------------------------适配器模式----------------------------------------------
概念: 将一个类的接口转换成客户希望的另一个接口
应用: 我们有时候一个接口不能直接给用户使用,我们可以根据用户需求二次封装现有接口.
步骤:4.1 创建一个常规业务接口
4.2 实现接口(至少2组)
4.3 普通方法调用(很麻烦)
4.4 扩展一个C业务CBizLogic,但是扩展的这个C业务类它并没有实现业务接口!
4.5 根据C业务增加一个适配器类(基于Class实现)在这个适配器中,继承C业务类,实现常规业务接口。
在实现业务接口中,我们可以调用C的业务,也可以扩展业务内容,这点就是AOP思想的体现。
4.6 基于对象,设计适配器。
【5】特别注意:我们在用适配器转换接口的时候,不仅是普通的转化,而且可以增加我们需要的其他自定义业务!
【6】什么时候选择适配器?当我们使用的类,和我们的接口不对应的时候,需要做一个适配。通常就是使用第三方类库的时候
比如第三方用C++写的,每次调用C++的类库都很麻烦,这时候我们可以封装成.NET类库,方便调用。
微软的COM组件就是典型的适配器。还有我们用的DataAdapter直接把数据填充到DataSet中,与具体数据格式无关系。
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("---------------------普通接口实现---------------------------");
IJieKou.Class1 my = new PrintImpl.PrintIm();
my.GetToInt(100);
my.ShowToString("zzl");
//上面是通过接口实现的
//现在有一个问题,如果需求发生了变化, 需要引入另外一个项目的接口,还要用原来的接口返回,这个怎么做 (使用适配器解决)
Console.WriteLine("---------------------适配器---------------------------");
IJieKou.Class1 myad = new AdapterM.AdapterOther();
myad.GetToInt(30);
myad.ShowToString("");
Console.WriteLine("---------------------适配器(解耦)---------------------------");
IJieKou.Class1 myado = new AdapterM.AdapterOtherXin();
myado.GetToInt(30);
myado.ShowToString("");
Console.Read();
}
}
}
namespace AdapterM
{
/// <summary>
/// 适配器类,在适配器里面吧需求变化的接口,封装到原来接口,(就是把新加的需要改变的接口适配到原来的接口)
/// </summary>
public class AdapterOther : otherLg.Othercl, IJieKou.Class1
{
#region 这种适配器是继承的方法,依赖度太高,
/// <summary>
/// 适配接口
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public int GetToInt(int parm)
{
//这个是我们需求变化的Othercl里面的接口,然后适配到原来的IJieKou接口上面
base.ShowOther();
return parm;
}
public void ShowToString(string parm)
{
Console.WriteLine("适配器模式");
}
#endregion
}
/// <summary>
/// 利用类的关系解耦适配器降低耦合度
/// </summary>
public class AdapterOtherXin : IJieKou.Class1
{
#region 上面的适配器耦合度太高,下面我们用类的关系来降低耦合度,解耦,
public otherLg.Othercl my = new otherLg.Othercl();
/// <summary>
/// 适配接口
/// </summary>
/// <param name="parm"></param>
/// <returns></returns>
public int GetToInt(int parm)
{
//这个是我们需求变化的Othercl里面的接口,然后适配到原来的IJieKou接口上面
my.ShowOther();
return parm;
}
public void ShowToString(string parm)
{
Console.WriteLine("解耦适配器模式");
}
#endregion
}
}
namespace IJieKou
{
/// <summary>
/// 接口类
/// </summary>
public interface Class1
{
int GetToInt(int parm);
void ShowToString(string parm);
}
}
namespace PrintImpl
{
/// <summary>
/// 接口实现类
/// </summary>
public class PrintIm:IJieKou.Class1
{
public int GetToInt(int parm)
{
Console.WriteLine("接口类实现GetToInt");
return parm;
}
public void ShowToString(string parm)
{
Console.WriteLine("接口类显示ShowToString" + parm);
}
}
}
namespace otherLg
{
/// <summary>
/// 业务变化需要用原来接口返回的其他接口或者方法
/// </summary>
public class Othercl
{
public void ShowOther()
{
Console.WriteLine("其他项目数据");
}
}
}
---------------------------------------外观模式----------------------------------------------
12. 外观模式(Facade),也称作“门面模式”
【1】概念:为不同子系统提供一个一致的访问“界面”,也就是通过本设计模式定义一个高层接口,该接口可以
使得对各个子系统的访问更加容易。
【2】举例:验车的过程,还是比较繁琐。“黄牛”。现在我只需要提供行车证和必要的经济费用即可。
【3】为什么使用外观模式?软件开发过程中,客户端程序有时候为了交互需要,可能和不通的子系统进行耦合,从而使得
各个子系统的变化,都会导致客户端程序的变化,只是典型的“紧耦合”,因此,为了解耦,我们把对各个子系统
的访问,再封装一次,并提供一个高层接口来访问。客户端只需要这个“稳定的高层接口”即可。
简单总结:外观模式就是为了简化多个子系统的访问。
【4】应用举例:计算机在线考试系统中,不同的业务分布在不同的系统中
实现步骤:第一,创建各个子系统
第二,模拟没有外观模式的调用
第三,使用外观模式做高层接口
第四,基于外观模式调用各个子系统
【5】总结:外观模式的实现核心主要是统一各个子系统的使用,接触客户端和各个子系统的高度依赖,子系统变化,
对客户端没有影响。
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("--------------------普通的使用------------------------");
Zzla za=new Zzla ();
za.Login("");
Zzlb zb=new Zzlb ();
zb.UpDateUser("");
ZzlC zc=new ZzlC ();
zc.OutLogin();
//上面这种方式可以,当时如果再用一个使用这样的项目,怎么办,在拷贝,代码冗余,
//下面我们使用适配器模式, 适配器模式就是整合各种系统,或者接口提供统一的处理接口
Console.WriteLine("--------------------外观模式------------------------");
SubSys sub = new SubSys();
sub.ShowAll();
Console.Read();
}
}
}
namespace ConsoleApplication4.waiguan
{
/// <summary>
/// 外观类
/// </summary>
public class SubSys
{
private Zzla za;
private Zzlb zb;
private ZzlC zc;
public SubSys()
{
za = new Zzla();
zb = new Zzlb();
zc = new ZzlC();
}
/// <summary>
/// 吧前面的(UI类调用个个接口或者系统的代码封装到这里,外观模式解决的事整合个个子系统或者接口提供一个封装的统一处理)
/// 这样如果 子系统变化了,如Zzla... UI配不用修改,在外观类里面修改就可以,如果多个地方在用,只用修改这一出就可以啦
/// </summary>
public void ShowAll()
{
Console.WriteLine("外观模式");
za.Login("");
zb.UpDateUser("");
zc.OutLogin();
}
}
}
namespace ConsoleApplication4.waiguan
{
/// <summary>
/// A类,登陆验证了
/// </summary>
public class Zzla
{
public void Login(string userName)
{
Console.WriteLine("用户登陆");
}
}
}
namespace ConsoleApplication4.waiguan
{
/// <summary>
/// B类 用户修改类
/// </summary>
public class Zzlb
{
public void UpDateUser(string userName)
{
Console.WriteLine("用户修改数据");
}
}
}
namespace ConsoleApplication4.waiguan
{
/// <summary>
/// 用户退出登陆
/// </summary>
public class ZzlC
{
public void OutLogin()
{
Console.WriteLine("用户退出登陆");
}
}
}
=========================================================================
外观模式和适配器模式比较:
外观模式是包装“一群对象”后,对外提供一个统一的“高层接口”,目的是“简化接口”。
适配器模式是包装“一个对象”后,将原对象的接口转换成“不同的接口”,目的是“改变接口”。