哈哈,小编又来了,这次给大家分享的是设计模式的第二大类型:结构型模式。废话不多说,看导图:
1、适配器模式(Adaper):将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可一起工作。
注:在Gof的设计模式中,适配器模式分为:类适配器模式和对象适配器模式。类适配器模式,通过多重继承对一个接口与另一个接口进行匹配。但,C#、VB.NET、JAVA等语言不支持多重继承(C++支持),即单根性,只有一个父类,此处只讲对象适配器。
解决的问题:需要的东西就在面前,但却不能使用,而短时间又无法改造它,于是我们就想办法适配它。如:因电压不同,用电源适配器,把电源变成需要的电压。
何时使用:使用一个已经存在的类,但其方法和你的要求不相同时,考虑用适配器模式。客户端代码统一调用同一接口。如:姚明去国外打球,但因语言不通,需要一个翻译员。
关键代码:
//球员
abstract class Player
{
public abstract void Attack();//进攻
public abstract void Defense();//防守
}
//外籍中锋
class ForeignCenter
{
//表明‘外籍中锋’只懂得中文‘进攻’、‘防守’
public void 进攻()
{
Console.WriteLine("外籍中锋{0}进攻",name);
}
public void 防守()
{
Console.WriteLine("外籍中锋{0}防守",name);
}
}
//翻译者
class Translator:Player
{
//声明并实例化一个内部‘外籍中锋’对象,表明翻译者与外籍球员有关联
private ForeignCenter wjzf = new ForeignCenter();
//翻译者将‘Attack’翻译为‘进攻’告诉外籍中锋
public override void Attack()
{
wjzf.进攻();
}
}
//客户端
Player ym = new Translator ("姚明");
ym.Attack();
2、桥接模式:将抽象部分与它的实现部分分离,使它们都可以独立地变化。
注:实现指的是抽象类与它的派生类用来实现自已的对象。如:手机既可以按照品牌类分类,也可以按照功能来分类。
核心意图:由于实现的方式有多种,就是把这些实现独立出来,让它们各自地变化。使得每种实现的变化不会影响其他实现,从而达到应对变化的目的。即减少耦合
关键:抽象手机品牌和抽象手机软件是聚合关系。手机品牌包含手机软件,但软件并不是品牌的一部分。
//手机品牌
abstract class HandsetBrand
{
protected HandsetSoft soft;
//设置手机软件
public void SetHandsetSoft(HandsetSoft soft)
{
this.soft = soft;
}
}
客户端:
HandsetBrand ab;
ab = new HandsetBrandN();
ab.SetHandsetSoft(new HandsetGame());
ab.Run();
ab.SetHandsetSoft(new HandsetAddressList());
ab.Run();
3、组合模式:将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性
如:人力资源部和财务部都继承公司,重写其方法。
何时使用:需求中体系部分与整体层次的结构时,及可忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时
好处:
1)定义了基本对象和组合对象,基本对象可以被组合成更复杂的组合对象,客户代码中,任何用到基本对象的地方都可以使用组合对象。
2)客户可以一致地使用组合结构和单个对象。
4、装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
优点:把类中的装饰功能从类中搬移去除,简化原有的类。有效地把类的核心职责和装饰功能区分开了,可以去除相关类中重复的装饰逻辑。
注意:装饰模式的装饰顺序很重要,最理想的情况是保证装饰之间彼此独立,这样可以任意的顺序进行组合。
class Finery:Person //关键代码
{
protected Person component;
//打扮
public void Decorate(Person component) //普通方法
{
this.component = component;
}
public override void Show() //方法重写
{
if (component !=null )
{
component.Show();
}
}
}
class TShirts:Finery
{
public override void Show()
{
Console.WriteLine("大T恤");
base.Show(); //调用父类方法
}
}
客户端:
//装饰过程 体现穿衣顺序
pqx.Decorate(xc);
kk.Decorate(pqx);
dtx.Decorate(kk);
dtx.Show();
5、外观模式(Façade):为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
总结:高层接口方法中调用了所有子类的方法。
客户端只需实例化接口,调用接口的方法即可。其他类的方法都被接口封装了,调用接口的方法即调用了其他所有类的方法。
何时使用:设计初期、开发阶段、维护大型系统时。
6、享元模式:运用共享技术有效地支持大量细粒度的对象。
目的:减少实例化的类的数量,节省存储开销
应用:功能类似,差别不大。
关键代码:
//网站工厂
class WebSiteFactory
{
private Hashtable flyweights = new Hashtable();
//获得网站分类
public WebSite GetWebSiteCategory(string key)
{
//判断是否存在这个对象,如果存在,则直接返回,若不存在,则实例化它再返回。
if (!flyweights .ContainsKey (key))
flyweights.Add(key, new ConcreteWebSite(key));
return ((WebSite)flyweights[key]);
}
}
static void Main(string[] args)
{
WebSiteFactory f = new WebSiteFactory();
WebSite fx = f.GetWebSiteCategory("产品展示");
fx.Use(new User("小菜"));
WebSite fy = f.GetWebSiteCategory("产品展示");//共享上方生成的对象,不再实例化
fx.Use(new User("大鸟"));
}
7、代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。
关键:Pursuit(追求者)和Proxy(代理)都有送礼物的三个方法,只不过Proxy送的礼物是Pursuit买的,实质是Pursuit送的。因此,追求者和代理都实现了同样的接口(送礼物的)
class Pursuit :IGiveGift //追求者类
{
SchoolGirl mm;
public Pursuit (SchoolGirl mm)
{
this.mm = mm;
}
}
class Proxy:IGiveGift //代理类
{
Pursuit gg;
public Proxy (SchoolGirl mm)
{
gg = new Pursuit(mm);
}
public void GiveDolls()
{
gg.GiveDolls(); //在实现方法中去调用“追求者”类的相关方法
}
}