zoukankan      html  css  js  c++  java
  • 温故而知新:设计模式之适配器模式(Adapter)

    借用terrylee的原话:

    Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。

    适配器模式再次体现了“面向接口编程,而非面向实现编程”这一精神。

    场景:

    有一个基于数据库的系统,里面的数据库操作就拿最常用的查询来说,主要是用SqlHelper类里的QueryData(string sql)这个方法来处理的,后来意外发现该方法实现上性能并不是最好(或者不能满足新的需要),而这时正好有一个第三方的DbHelper程序集,写得很成熟性能也不错,但唯一不足的是里面的查询方法签名是SelectData(string sql),怎么办?所有引用SqlHelper的地方全部修改,重头编译么?No,没人会想这样


    先看下原来的代码:

    using System;
    using System.Data;

    namespace Adapter
    {
        
    class Program
        {
            
    static void Main(string[] args)
            {
                IDBHelper dbhelper 
    = new SqlHelper();
                dbhelper.QueryData(
    "Select * from TableA");

                Console.ReadKey();
            }
        }

        
    public interface IDBHelper 
        {
            DataSet QueryData(
    string sql);
        }

        
    public class SqlHelper : IDBHelper 
        {
            
    public DataSet QueryData(string sql) 
            {
                Console.WriteLine(
    "QueryData is Called,the sql is :\"{0}\"",sql);
                
    return new DataSet();//这里演示起见,就直接返回一个DataSet实例完事 :)
            }
        }
    }

    如何在尽量不影响原有客户端代码的情况下,用新的DbHelper来取代旧的SqlHelper呢?

    假如第三方的DBHelper结构如下:

    /// <summary>
        
    /// 第三方的新dbHelper,实际场景中,这个类通常都是封装在程序集中以dll提供,客户端程序无法修改
        
    /// </summary>
        public class DbHelper 
        {
            
    public DataSet SelectData(string sql)
            {
                Console.WriteLine(
    "SelectData is Called,the sql is :\"{0}\"", sql);
                
    return new DataSet();//这里演示起见,就直接返回一个DataSet实例完事 :)
            }
        }

    可以新增一个适配器:

        /// <summary>
        
    /// 新增的适配器
        
    /// </summary>
        public class DBHelperAdapter : IDBHelper 
        {
            
    private DbHelper _dbHelper;

            
    public DBHelperAdapter(DbHelper dbHelper) 
            {
                
    this._dbHelper = dbHelper;
            }

            
    public DataSet QueryData(string sql)         
            {
                
    return _dbHelper.SelectData(sql);
            }

        }

    这样原有的客户端程序,只需要把
    IDBHelper dbhelper = new SqlHelper();

    改成:

    IDBHelper dbhelper = new DBHelperAdapter(new DbHelper()); 就万事大吉了,当然你可以用配置文件+反射,完全解耦,此处略过

    反思:

    本例中之所以能轻易将新的类替换旧的类,主要得益于旧的代码仅依赖于抽象(即接口IDBHelper),而非具体的实现(即类SqlHelper),否则也不可能达到最终效果。

    OO原则中的"面对接口编码","依赖倒置"的妙处也就在于此。

    最后给出类图:

    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    iOS BCD编码
    Java泛型解析(02):通配符限定
    HDU 5317 RGCDQ(素数个数 多校2015啊)
    通过getElementById来取得Form里的表单元素
    关系型数据库工作原理-快速缓存(翻译自Coding-Geek文章)
    cocos2d-x之道~制作第一款文字游戏(二)
    Html5实现手机九宫格password解锁功能
    [Python] 字典推导 PEP 274 -- Dict Comprehensions
    NYOJ 36 最长公共子序列 (还是dp)
    【设计模式】学习笔记5:工厂模式
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/1659034.html
Copyright © 2011-2022 走看看