zoukankan      html  css  js  c++  java
  • 02.10 桥模式

    设计模式——桥模式

    需求

    从现实故事说起,长虹与海尔都是大的电视机生产商,都能够生产21英寸与37英寸的电视,这个问题应该如何建模呢?下面尝试使用继承关系实现:

        // 定义一个制造商接口

        public interface IManufacturer { void ShowName(); }

        // 再定义一个电视接口

        public interface ITV { void Produce(); }

        // 定义2个电视机子类

        public class TV21inches : ITV   // 21英寸电视机

        {

            public void Produce() { Console.WriteLine("生产21英寸电视机!"); }

        }

        public class TV37inches : ITV   // 37英寸电视机

        {

            public void Produce() { Console.WriteLine("生产37英寸电视机!"); }

        }

        // 接下来只能玩万恶的多重继承了

        public class ChanghongTV21inches : TV21inches, IManufacturer    // 长虹21英寸电视机

        {

            public void ShowName() { Console.Write("长虹"); }

            public void Produce() { base.Produce(); }

        }

        public class ChanghongTV37inches : TV37inches, IManufacturer    // 长虹37英寸电视机

        {

            public void ShowName() { Console.Write("长虹"); }

            public void Produce() { base.Produce(); }

        }

        public class HaierTV21inches : TV21inches, IManufacturer    // 海尔21英寸电视机

        {

            public void ShowName() { Console.Write("海尔"); }

            public void Produce() { base.Produce(); }

        }

        public class HaierTV37inches : TV37inches, IManufacturer    // // 海尔37英寸电视机

        {

            public void ShowName() { Console.Write("海尔"); }

            public void Produce() { base.Produce(); }

        }

    如果再有新的制造商或者电视规格需要加进来呢?那样继承关系真是复杂的不得了!

    这样的需求上升到理论的层次,就可以总结为:系统具有多维角度的分类,每一种分类都有可能变化,却还需要可以随意组合。显然使用继承关系会使得设计非常复杂;而且使用继承关系会使得多维角度的组合在编译期就固定化。

    定义

    桥模式(Bridge Pattern)的GoF定义,将抽象部分与它的实现部分分离,使的抽象和实现都可以独立地变化。

    不好理解吧,因为我们大多习惯了继承关系里的抽象类/派生类(或者接口/实现类)的概念,而桥接模式里的“抽象”与“实现”根本不是这个意思。

    这里用角色的概念来说明更好理解:当某个问题具有多维角度分类时,将其拆分为Implementor(实现者)与Abstraction(抽象者)。Implementor(实现者)提供了一些原始的功能,而Abstraction(抽象者)对实现者及其原始操作进行了更高层次的封装。

      

      

    如图所示,桥模式(Bridge Pattern)由4部分组成:(1)抽象的实现者(Abstract Implementor),定义实现者的规格;(2)具体实现者(Concrete Implementor),实现抽象的实现者(Abstract Implementor)定义的那些原始功能;(3)父级抽象者(Abstraction),为实现者(Implementor)定义一个抽象的访问接口,内部维护一个对实现者(Implementor)的引用,便于调用实现者提供的那些基本操作以进行附加功能;(4)子级提炼抽象者(Refined Abstraction),实现父级抽象者,并且将抽象者的操作提炼。桥接模式(Bridge Pattern)就这样将某个问题抽象部分与该问题的实现部分相分离,使得两者都可以独立变化,并能够动态结合。

    案例:电视机生产

    还是回到电视机生产的问题,我们把电视机与生产商分离开来,各自单独设计。

      

        // 将电视机作为Implementor,定义一个电视机接口

        public interface ITV { void Produce(); }

        // 定义Implementor的具体类,定义2个电视机子类

        public class TV21inches : ITV   // 21英寸电视机

        {

            public void Produce() { Console.WriteLine("生产21英寸电视机!"); }

        }

        public class TV37inches : ITV   // 37英寸电视机

        {

            public void Produce() { Console.WriteLine("生产37英寸电视机!"); }

        }

        // 将生产商作为Abstraction,定义一个抽象的生产商类,在其内包裹一个电视机接口

        public abstract class Manufacturer

        {

            public Manufacturer(ITV tv) { this._TV = tv; }

            private ITV _TV;

            public virtual void ProcuedureTV() { this._TV.Produce(); }

        }

        // 在Abstraction子类实现中提炼抽象

        public class ChanghongTV : Manufacturer // 长虹生产电视机

        {

            public ChanghongTV(ITV tv) : base(tv) { }

            public override void ProcuedureTV()

            {

                Console.Write("长虹");

                base.ProcuedureTV();

            }

        }

        public class HaierTV : Manufacturer // 海尔生产电视机

        {

            public HaierTV(ITV tv) : base(tv) { }

            public override void ProcuedureTV()

            {

                Console.Write("海尔");

                base.ProcuedureTV();

            }

        }

       

        class Program

        {       

            static voidMain(string[] args)

            {

                // 客户程序

                new ChanghongTV(new TV21inches()).ProcuedureTV();

                new ChanghongTV(new TV37inches()).ProcuedureTV();

                new HaierTV(new TV21inches()).ProcuedureTV();

                new HaierTV(new TV37inches()).ProcuedureTV();

            }

        }

    案例:适用于大多数需要数据库访问的界面编程

    学习过三层结构后,都会觉得对中间层的理解与实现清晰多了,但是界面层的是实现比中间层复杂化、不可预测化多了。现在许多有经验的程序员,总结了大多数需要数据库访问界面的规律,设计了类似下面图中的接口与架构,希望对你有用。

      

    优缺点

    优点:使用桥接模式,能够比使用继承关系更灵活;它可以使抽象和实现分离,降低了耦合关系;还有其它好处,分离开的抽象与实现还允许自由组合,动态切换;减少子类个数等等。当有新的抽象或者实现需要增加时,只需要继承一个抽象或者继承一个实现即可。

    缺点:(1)桥接模式的使用会增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程;(2)桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性,如何正确识别两个独立维度也需要一定的经验积累。

    适用场景

    当系统有多维角度分类时,而每一种分类又有可能变化,可以考虑使用桥接模式。桥模式也是继承关系的一个替代方案。

    补充

  • 相关阅读:
    ASP.NET MVC 1.0 + spring.net 1.2.0.20288 + NHibernate 2.0.1.4000整合笔记(三)——NHibernate配置
    ASP.NET MVC: 使用自定义 ModelBinder
    设计模式和重构的学习心得体验
    ASP.NET MVC 1.0 + spring.net 1.2.0.20288 + NHibernate 2.0.1.4000整合笔记(四)——整合asp.net mvc
    获取外键关联的实体对象
    Ado.net Entity Framework 中的多对多查询
    Oxite分析笔记之数据验证
    ASP.NET MVC 1.0 + spring.net 1.2.0.20288 + NHibernate 2.0.1.4000整合笔记(二)——spring.net配置
    WPF之依赖属性的继承
    WCF之传递较长字符串(参数)
  • 原文地址:https://www.cnblogs.com/sagahu/p/2715311.html
Copyright © 2011-2022 走看看