一页中总结结构类型的设计模式
机构类型设计模式目录,之前的创建类型的设计模式介绍看这里
1. 适配器模式(将某个类的接口转换成客户端期望的另一个接口表示。适配器模式可以消除由于接口不匹配所造成的类兼容性问题。)引用院子Learning hard的示例,比较经典的插头例子
using System; /// 这里以插座和插头的例子来诠释适配器模式 /// 现在我们买的电器插头是2个孔,但是我们买的插座只有3个孔的 /// 这是我们想把电器插在插座上的话就需要一个电适配器 namespace 设计模式之适配器模式 { /// <summary> /// 客户端,客户想要把2个孔的插头 转变成三个孔的插头,这个转变交给适配器就好 /// 既然适配器需要完成这个功能,所以它必须同时具体2个孔插头和三个孔插头的特征 /// </summary> class Client { static void Main(string[] args) { // 现在客户端可以通过电适配要使用2个孔的插头了 IThreeHole threehole = new PowerAdapter(); threehole.Request(); Console.ReadLine(); } } /// <summary> /// 三个孔的插头,也就是适配器模式中的目标角色 /// </summary> public interface IThreeHole { void Request(); } /// <summary> /// 两个孔的插头,源角色——需要适配的类 /// </summary> public abstract class TwoHole { public void SpecificRequest() { Console.WriteLine("我是两个孔的插头"); } } /// <summary> /// 适配器类,接口要放在类的后面 /// 适配器类提供了三个孔插头的行为,但其本质是调用两个孔插头的方法 /// </summary> public class PowerAdapter:TwoHole,IThreeHole { /// <summary> /// 实现三个孔插头接口方法 /// </summary> public void Request() { // 调用两个孔插头方法 this.SpecificRequest(); } } }
2. 桥接模式(将一个抽象与实现解耦,以便两者可以独立的变化。)我看到原有有举例使用在数据库访问层面上,将不同数据库桥接到抽象的操作类,是个非常好的应用。
//抽象或者接口 //选台和播放 interface IVideoSource { string GetTvGuide(); string PlayVideo(); } //抽象或者接口实现 ---》不同的电台 class LocalCabelTv : IVideoSource { const string SOURCE_NAME = "Local Cabel TV"; string IVideoSource.GetTvGuide() { return string.Format("Getting TV guide from - {0}", SOURCE_NAME); } string IVideoSource.PlayVideo() { return string.Format("Playing - {0}", SOURCE_NAME); } } //具体实现 电台2 class LocalDishTv : IVideoSource { const string SOURCE_NAME = "Local DISH TV"; string IVideoSource.GetTvGuide() { return string.Format("Getting TV guide from - {0}", SOURCE_NAME); } string IVideoSource.PlayVideo() { return string.Format("Playing - {0}", SOURCE_NAME); } } //智能电视,桥接载体,这个载体很重要 class MySuperSmartTV { IVideoSource currentVideoSource = null; public IVideoSource VideoSource { get { return currentVideoSource; } set { currentVideoSource = value; } } public void ShowTvGuide() { if (currentVideoSource != null) { Console.WriteLine(currentVideoSource.GetTvGuide()); } else { Console.WriteLine("Please select a Video Source to get TV guide from"); } } public void PlayTV() { if (currentVideoSource != null) { Console.WriteLine(currentVideoSource.PlayVideo()); } else { Console.WriteLine("Please select a Video Source to play"); } } } //客户端调用 class SuperSmartTvController { static void Main(string[] args) { MySuperSmartTV myTv = new MySuperSmartTV(); //载体 Console.WriteLine("请选择电台节目"); ConsoleKeyInfo input = Console.ReadKey(); // 用户选择不同的电台后 将节目桥接给电视播放 switch (input.KeyChar) { case '1': myTv.VideoSource = new LocalCabelTv(); break; case '2': myTv.VideoSource = new LocalDishTv(); break; } Console.WriteLine(); //选台显示 myTv.ShowTvGuide(); //电视开始播放 myTv.PlayTV(); Console.WriteLine(); } }
3.组合模式(把多个对象组成树状结构来表示局部与整体,这样用户可以一样的方式来对待单个对象和对象的组合。)
组合模式为了使用户可以用一样的方式对待单个对象和组合对象的目的,那么都必须实现一样的基类或者接口来实现,这就是它的原理。
//继承相同的基类或者接口。 组件 public abstract class Component { protected readonly string name; protected Component(string name) { this.name = name; } public abstract void Operation(); public abstract void Display(int depth); } //实现单个对象 子组件 public class Leaf : Component { public Leaf(string name) : base(name) { } public override void Operation() { Console.WriteLine("Leaf."); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); } } //组合组件对象 class Composite : Component { private readonly List<Component> _children = new List<Component>(); public Composite(string name) : base(name) { } //组合叶子组件 删除或者增加 public void AddChild(Component component) { _children.Add(component); } public void RemoveChild(Component component) { _children.Remove(component); } public override void Display(int depth) { Console.WriteLine(new String('-', depth) + name); foreach (Component component in _children) { component.Display(depth + 2); } } public override void Operation() { string message = string.Format("Composite with {0} child(ren).", _children.Count); Console.WriteLine(message); } } //客户端调用 static class Program { static void Main() { //根组合组件增加俩单个对象组件 var root = new Composite("root"); root.AddChild(new Leaf("Leaf 1")); root.AddChild(new Leaf("Leaf 2")); //第二个组合组件增加俩单个对象组件 var comp = new Composite("Composite C"); comp.AddChild(new Leaf("Leaf C.1")); comp.AddChild(new Leaf("Leaf C.2")); //将第二个组合组件计入根组合组件 root.AddChild(comp); root.AddChild(new Leaf("Leaf 3")); //实例化一个单个组件,并加入到根组合组件中 var leaf = new Leaf("Leaf 4"); root.AddChild(leaf); root.RemoveChild(leaf); //统一调用所有的 root.Display(1); } }
4、装饰模式(有时也叫修饰模式,它是向某个对象动态地添加更多的功能。修饰模式是除类继承外另一种扩展功能的方法。)
//一个组件基类 public abstract class ComponentBase { public abstract void Operation(); } //实现基类的标准组件 class ConcreteComponent : ComponentBase { public override void Operation() { Console.WriteLine("ConcreteComponent.Operation()"); } } //为了给Operation方法增加额外功能,集成自组件基类的基类,起到装饰作用 public abstract class DecoratorBase : ComponentBase { private readonly ComponentBase _component; protected DecoratorBase(ComponentBase component) { _component = component; } public override void Operation() { _component.Operation(); } } //增加额外功能给Operation方法,这里扩展类中调用的是扩展的基类 public class ConcreteDecorator : DecoratorBase { public ConcreteDecorator(ComponentBase component) : base(component) { } public override void Operation() { base.Operation(); Console.WriteLine("这里可以增加额外的功能或者在该类中实现其他方法在此处调用"); } } //客户端调用 static class Program { static void Main() { //我是一个标准组件 var component = new ConcreteComponent(); //扩展了功能的组件 var decorator = new ConcreteDecorator(component); decorator.Operation(); //该方法被增强了其他功能 } }
5、外观模式(为子系统中的一组接口提供一个一致的界面, 外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。)
这个模式现实中使用在外面经常在系统架构中的包装层(Facade层),将很多子类都封装在一起,让后共外部调用。
//A子系统 功能方法返回数字1 public class Class1A { public int Method1A() { Console.WriteLine("Class1A.Method1A return value: 1"); return 1; } } //B子系统 public class Class1B { public int Method1B(int param) { Console.WriteLine("Class1B.Method1B return value: {0}",param+1); return param+1; } } //2A子系统 public class Class2A { public int Method2A(int param) { Console.WriteLine("Class2A.Method2A return value: {0}",param+2); return param+2; } } //2B子系统 public class Class2B { public void Method2B(int param1, int param2) { Console.WriteLine("Class2B.Method2B return value: {0}", param1+param2 ); } } //外观模式的包装层 public class Facade { public void PerformAction() { var c1a = new Class1A(); var c1b = new Class1B(); var c2a = new Class2A(); var c2b = new Class2B(); var result1a = c1a.Method1A(); var result1b = c1b.Method1B(result1a); var result2a = c2a.Method2A(result1a); c2b.Method2B(result1b, result2a); } } //外部客户端调用 static class Program { static void Main() { //供外部统一调用 Facade facade = new Facade(); facade.PerformAction(); } }
该模式有点类似原型模式(建造类型的),不同的是享元模式是结构类型的模式,原始对象(共享的对象,即不可变部分。俗称不可变内部状态)可能产生不同的小颗粒对象(可变部分,例如参数。俗称可变外部状态),封装了原始对象进入一个工厂,使用中可以不必重复创建对象。
//抽象层,提供共享使用要实现的内部方法 public abstract class FlyweightBase { public abstract void StatefulOperation(object o); } //共享的类 public class ConcreteFlyweight : FlyweightBase { public override void StatefulOperation(object o) { Console.WriteLine(o); } } //非共享类 public class UnsharedFlyweight : FlyweightBase { private object _state; public override void StatefulOperation(object o) { _state = o; Console.WriteLine(_state); } } //共享工厂类,将同对象细粒度的对象保存到hashtable public class FlyweightFactory { private readonly Hashtable _flyweights = new Hashtable(); public FlyweightBase GetFlyweight(string key) { if (_flyweights.Contains(key)) { return _flyweights[key] as FlyweightBase; } var newFlyweight = new ConcreteFlyweight(); _flyweights.Add(key, newFlyweight); return newFlyweight; } } //客户端调用 static class Program { static void Main() { int extrinsicstate = 22; //一下三个是共享三个细粒度对象,其实他们只有一个原对象实例 var factory = new FlyweightFactory(); var flyweightA = factory.GetFlyweight("A"); flyweightA.StatefulOperation(--extrinsicstate); var flyweightB = factory.GetFlyweight("B"); flyweightB.StatefulOperation(--extrinsicstate); var flyweightC = factory.GetFlyweight("C"); flyweightC.StatefulOperation(--extrinsicstate); //非共享的对象 var unsharedFlyweight = new UnsharedFlyweight(); unsharedFlyweight.StatefulOperation(--extrinsicstate); } }
代理模式客户端不能直接访问原对象,只能通过代理中介访问。某些情况就是客户端无法访问原对象或者更重要的是代理要做点手脚才让你访问呢!,就只能请代理来帮忙了。
//代理及实际对象的基类 public abstract class SubjectBase { public abstract void Operation(); } //实际原对象 public class RealSubject : SubjectBase { public override void Operation() { Console.WriteLine("RealSubject.Operation"); } } //代理 public class Proxy : SubjectBase { private RealSubject _realSubject; public override void Operation() { if (_realSubject == null) _realSubject = new RealSubject(); _realSubject.Operation(); } } //客户端使用代理访问原对象的方法 static class Program { static void Main() { var proxy = new Proxy(); proxy.Operation(); } }
劳神费力的,点歌赞打赏打赏