在C#开发中,设计模式是解决常见问题的一种可复用的解决方案。以下是一些常用的C#设计模式:
一、创建型模式
单例模式(Singleton)
目的:确保一个类只有一个实例,并提供一个全局访问点。
实现方式:通过私有化构造函数和静态字段来控制实例的创建。例如:
publicclassSingleton{privatestaticSingletoninstance;privateSingleton(){}publicstaticSingletonInstance{get{if(instance==null)instance=newSingleton();returninstance;}}}适用场景:日志记录器、配置管理器等需要全局唯一实例的场景。
工厂模式(Factory)
- 目的:封装对象的创建逻辑,提供统一的接口来创建对象。
- 实现方式:定义一个工厂类,通过工厂方法来创建对象。例如:
publicinterfaceIProduct{voidShow();}publicclassConcreteProductA:IProduct{publicvoidShow(){Console.WriteLine("Product A");}}publicclassConcreteProductB:IProduct{publicvoidShow(){Console.WriteLine("Product B");}}publicclassFactory{publicIProductCreateProduct(stringtype){if(type=="A")returnnewConcreteProductA();elseif(type=="B")returnnewConcreteProductB();returnnull;}} - 适用场景:当需要根据不同的条件创建不同类型的对象时。
抽象工厂模式(Abstract Factory)
- 目的:创建一组相关或依赖的对象,而无需指定它们的具体类。
- 实现方式:定义一个抽象工厂接口和多个具体工厂类。例如:
publicinterfaceIProductA{voidShow();}publicinterfaceIProductB{voidShow();}publicclassConcreteProductA1:IProductA{publicvoidShow(){Console.WriteLine("Product A1");}}publicclassConcreteProductB1:IProductB{publicvoidShow(){Console.WriteLine("Product B1");}}publicclassConcreteProductA2:IProductA{publicvoidShow(){Console.WriteLine("Product A2");}}publicclassConcreteProductB2:IProductB{publicvoidShow(){Console.WriteLine("Product B2");}}publicinterfaceIFactory{IProductACreateProductA();IProductBCreateProductB();}publicclassConcreteFactory1:IFactory{publicIProductACreateProductA(){returnnewConcreteProductA1();}publicIProductBCreateProductB(){returnnewConcreteProductB1();}}publicclassConcreteFactory2:IFactory{publicIProductACreateProductA(){returnnewConcreteProductA2();}publicIProductBCreateProductB(){returnnewConcreteProductB2();}} - 适用场景:当需要创建一系列相关的产品对象时。
建造者模式(Builder)
- 目的:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
- 实现方式:定义一个建造者接口和多个具体建造者类。例如:
publicclassProduct{privateList<string>parts=newList<string>();publicvoidAdd(stringpart){parts.Add(part);}publicvoidShow(){foreach(stringpartinparts){Console.WriteLine(part);}}}publicinterfaceIBuilder{voidBuildPartA();voidBuildPartB();ProductGetResult();}publicclassConcreteBuilder:IBuilder{privateProductproduct=newProduct();publicvoidBuildPartA(){product.Add("PartA");}publicvoidBuildPartB(){product.Add("PartB");}publicProductGetResult(){returnproduct;}}publicclassDirector{privateIBuilderbuilder;publicDirector(IBuilderbuilder){this.builder=builder;}publicvoidConstruct(){builder.BuildPartA();builder.BuildPartB();}} - 适用场景:当需要构建一个复杂的对象时。
原型模式(Prototype)
- 目的:通过复制现有的实例来创建新的实例,而不是通过新建实例。
- 实现方式:定义一个原型接口,实现克隆方法。例如:
publicinterfaceIPrototype{IPrototypeClone();}publicclassConcretePrototype:IPrototype{privatestringfield;publicConcretePrototype(stringfield){this.field=field;}publicIPrototypeClone(){return(IPrototype)this.MemberwiseClone();}publicvoidShow(){Console.WriteLine(field);}} - 适用场景:当需要创建大量相似的对象时。
二、结构型模式
- 适配器模式(Adapter)
- 目的:将一个类的接口转换成客户端所期望的另一种接口。
- 实现方式:定义一个适配器类,实现客户端期望的接口,并在内部封装被适配的类。例如:
publicinterfaceITarget{voidRequest();}publicclassAdaptee{publicvoidSpecificRequest(){Console.WriteLine("Adaptee SpecificRequest");}}publicclassAdapter:ITarget{privateAdapteeadaptee;publicAdapter(){adaptee=newAdaptee();}publicvoidRequest(){adaptee.SpecificRequest();}} - 适用场景:当需要使用一个不符合接口要求的类时。
- 装饰器模式(Decorator)
- 目的:动态地给一个对象添加额外的功能。
- 实现方式:定义一个装饰器类,继承被装饰的类,并在内部封装被装饰的对象。例如:
publicinterfaceIComponent{voidOperation();}publicclassConcreteComponent:IComponent{publicvoidOperation(){Console.WriteLine("ConcreteComponent Operation");}}publicabstractclassDecorator:IComponent{protectedIComponentcomponent;publicDecorator(IComponentcomponent){this.component=component;}publicvirtualvoidOperation(){component.Operation();}}publicclassConcreteDecoratorA:Decorator{publicConcreteDecoratorA(IComponentcomponent):base(component){}publicoverridevoidOperation(){base.Operation();AddedBehavior();}privatevoidAddedBehavior(){Console.WriteLine("ConcreteDecoratorA AddedBehavior");}}publicclassConcreteDecoratorB:Decorator{publicConcreteDecoratorB(IComponentcomponent):base(component){}publicoverridevoidOperation(){base.Operation();AddedBehavior();}privatevoidAddedBehavior(){Console.WriteLine("ConcreteDecoratorB AddedBehavior");}} - 适用场景:当需要动态地给对象添加功能时。
- 代理模式(Proxy)
- 目的:为其他对象提供一种代理以控制对这个对象的访问。
- 实现方式:定义一个代理类,实现与被代理类相同的接口,并在内部封装被代理的对象。例如:
publicinterfaceISubject{voidRequest();}publicclassRealSubject:ISubject{publicvoidRequest(){Console.WriteLine("RealSubject Request");}}publicclassProxy:ISubject{privateRealSubjectrealSubject;publicvoidRequest(){if(realSubject==null){realSubject=newRealSubject();}PreRequest();realSubject.Request();PostRequest();}privatevoidPreRequest(){Console.WriteLine("Proxy PreRequest");}privatevoidPostRequest(){Console.WriteLine("Proxy PostRequest");}} - 适用场景:当需要控制对对象的访问时。
- 外观模式(Facade)
- 目的:为复杂的子系统提供一个简单的接口。
- 实现方式:外观模式 (Facade Pattern)是一种结构型设计模式。
它的核心思想非常直观:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
简单来说,就是**“化繁为简”**。你不需要知道内部复杂的运作机制,只需要通过一个统一的入口(Facade)就能完成复杂的操作。
1. 生活类比:餐厅点餐
- 没有外观模式:你想吃一顿饭,需要自己去厨房找厨师炒菜、去仓库找服务员拿盘子、去收银台结账。你需要和多个部门打交道,流程极其复杂。
- 有外观模式:你只需要面对服务员(Facade)。你告诉服务员“我要一份牛排”,服务员会在后台协调厨房、仓库和收银台。你不需要关心牛排是怎么做的,只需要和服务员交互。
2. 代码实现示例
假设我们要构建一个家庭影院系统,包含投影仪、灯光、音响、DVD播放器等多个组件。
第一步:定义复杂的子系统类
这些类各自独立,功能单一,但组合起来很麻烦。
publicclassProjector{publicvoidOn()=>Console.WriteLine("Projector is ON");publicvoidOff()=>Console.WriteLine("Projector is OFF");publicvoidWideScreenMode()=>Console.WriteLine("Projector in wide screen mode");}publicclassLights{publicvoidDim(intlevel)=>Console.WriteLine($"Lights dimmed to{level}%");publicvoidOn()=>Console.WriteLine("Lights are ON");}publicclassScreen{publicvoidDown()=>Console.WriteLine("Screen rolling down");publicvoidUp()=>Console.WriteLine("Screen rolling up");}publicclassDvdPlayer{publicvoidOn()=>Console.WriteLine("DVD Player is ON");publicvoidOff()=>Console.WriteLine("DVD Player is OFF");publicvoidPlay(stringmovie)=>Console.WriteLine($"Playing movie:{movie}");publicvoidStop()=>Console.WriteLine("Movie stopped");}第二步:创建外观类 (Facade)
外观类持有所有子系统的引用,并封装了复杂的调用逻辑。
publicclassHomeTheaterFacade{privateProjector_projector;privateLights_lights;privateScreen_screen;privateDvdPlayer_dvd;publicHomeTheaterFacade(Projectorprojector,Lightslights,Screenscreen,DvdPlayerdvd){this._projector=projector;this._lights=lights;this._screen=screen;this._dvd=dvd;}// 封装“看电影”的复杂流程publicvoidWatchMovie(stringmovie){Console.WriteLine("--- Get ready to watch a movie ---");_lights.Dim(10);_screen.Down();_projector.On();_projector.WideScreenMode();_dvd.On();_dvd.Play(movie);Console.WriteLine("--- Movie started! ---");}// 封装“结束电影”的复杂流程publicvoidEndMovie(){Console.WriteLine("--- Shutting down home theater ---");_dvd.Stop();_dvd.Off();_projector.Off();_screen.Up();_lights.On();Console.WriteLine("--- Home theater off ---");}}第三步:客户端调用
客户端不再需要知道Projector、Lights等类的存在,只与HomeTheaterFacade交互。
publicclassClient{publicstaticvoidMain(string[]args){// 初始化子系统varprojector=newProjector();varlights=newLights();varscreen=newScreen();vardvd=newDvdPlayer();// 创建外观对象varhomeTheater=newHomeTheaterFacade(projector,lights,screen,dvd);// 简单调用homeTheater.WatchMovie("Iron Man");Console.WriteLine();homeTheater.EndMovie();}}3. 外观模式的优点
- 简化接口:将复杂的子系统逻辑封装起来,提供给客户端一个简单的接口。
- 解耦:客户端与子系统解耦。子系统的内部变化(如更换投影仪品牌)不会影响到客户端,只要外观类的接口不变。
- 提高安全性:可以限制客户端对子系统的访问权限,只暴露必要的方法。
4. 适用场景
- 当你要为一个复杂子系统提供一个简单接口时。
- 当客户端与多个子系统类之间存在紧密耦合时,引入 Facade 可以将它们分离。
- 当你需要分层架构时(例如:Service 层作为 DAO 层的外观,Controller 层作为 Service 层的外观)。
5. 注意事项
- 不要过度封装:外观模式不应该阻止高级用户直接访问子系统类。如果用户需要更精细的控制,应该允许他们绕过 Facade 直接使用子系统。
- Facade 不是单例:虽然很多情况下 Facade 可以是单例,但这并非强制要求。
- 与代理模式的区别:代理模式侧重于控制访问(如权限、延迟加载),而外观模式侧重于简化接口。