【C#设计模式-适配器模式】

1.适配器模式一般的额使用情况:

在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用。但是新环境要求的接口是这些现存对象所不满足的。如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?Adapter 模式为我们很好的解决这类问题。

结构:


2.列举生活中存在的例子进行说明:

这里我们以日志记录程序为Demo说明,在任何一套软件中都会有对应的日志管理模块,假如如果我们在开发软件中的日记记录采用第三方的日志组件进行日志记录,它采用的是Log.Write("写日志");方式,我们的程序在开发中,大量实例化日记记录对象,采用的Log.Write()方式进行日志记录,但是现在第三方的日志组件现在不免费了,需要收费了,于是我们打算使用一种新的日志管理模块,只不过它提供给我们的API接口是采用Log.WriteLog("新的写日志的方式");进行日志记录。这个时候问题就出现了,如何应对这种迁移的变化呢?

先看原来日志的接口,这里采用的是Write(“写日志”);

 /// <summary>
    /// 原来的日志记录接口
    /// </summary>
    public interface ILogTarget
    {
        /// <summary>
        /// 原来的写日志方法
        /// </summary>
        void Write(string info);
    }
然而现在的写日志的接口,采用的是WriteLog("写日志");里面实现了写日志的新的方式:将日志写到文件中,数据库中

    /// <summary>
    /// 抽象写日志类
    /// </summary>
    public abstract class LogAdaptee
    {
        /// <summary>
        /// 写日志
        /// </summary>
        public abstract void WriteLog(string info);
    }

   /// <summary>
    /// 写文件日志记录
    /// </summary>
    public class FileLog:LogAdaptee
    {
        /// <summary>
        /// 写日志到文件中
        /// </summary>
        public override void WriteLog(string info)
        {
            Console.WriteLine("记录到文本文件:"+info);
        }
    }
    /// <summary>
    /// 往数据库中写日志
    /// </summary>
    public class DatabaseLog:LogAdaptee
    {
        /// <summary>
        /// 重写写日志方法
        /// </summary>
        public override void WriteLog(string info)
        {
            Console.WriteLine("记录到数据库:"+info);
        }
    }
如何使用者两个新对象中的方式,替换原来的写日志的方式呢?

    /// <summary>
    /// 采用新的写日志的方式,写入到数据库中
    /// </summary>
    public class DatabaseLogAdapter:DatabaseLog,ILogTarget
    {
        /// <summary>
        /// 在重写ILogTarget接口中的的Write方法里面调用新的写日志的方式WriteLog
        /// </summary>
        public void Write(string info)
        {
            WriteLog(info);
        }
    }
    /// <summary>
    /// 采用新的写日志的方式,写入到文本文件
    /// </summary>
    public class FileLogAdapter : FileLog, ILogTarget
    {
        /// <summary>
        /// 在重写ILogTarget接口中的的Write方法里面调用新的写日志的方式WriteLog
        /// </summary>
        public void Write(string info)
        {
            this.WriteLog(info);
        }
    }
调用依据使用的原来写日志的方法,但是确实使用的新的写日志的方式:

 /// <summary>
    /// 类 适配器模式(Adapter Pattern)
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            ILogTarget dbLog = new DatabaseLogAdapter();
            dbLog.Write("程序启动成功");
            dbLog = new FileLogAdapter();
            dbLog.Write("程序启动成功");
        }
    }
上面的方式采用的是类适配器的方式实现了新的日志功能的迁移变化,下面我们使用对象适配器,可以区别发现两种方式的特别之处>

原来写日志的方法依旧不变:Write("写日志");

    /// <summary>
    /// 原来的日志记录接口
    /// </summary>
    public interface ILogTarget
    {
        /// <summary>
        /// 原来的写日志方法
        /// </summary>
        void Write(string info);
    }
现在的写日志的接口,采用的是WriteLog("写日志");里面实现了写日志的新的方式:将日志写到文件中,数据库中
    /// <summary>
    /// 抽象写日志类
    /// </summary>
    public abstract class LogAdaptee
    {
        /// <summary>
        /// 写日志
        /// </summary>
        public abstract void WriteLog(string info);
    }
   /// <summary>
    /// 写文件日志记录
    /// </summary>
    public class FileLog:LogAdaptee
    {
        /// <summary>
        /// 写日志到文件中
        /// </summary>
        public override void WriteLog(string info)
        {
            Console.WriteLine("记录到文本文件:"+info);
        }
    }
    /// <summary>
    /// 往数据库中写日志
    /// </summary>
    public class DatabaseLog:LogAdaptee
    {
        /// <summary>
        /// 重写写日志方法
        /// </summary>
        public override void WriteLog(string info)
        {
            Console.WriteLine("记录到数据库:"+info);
        }
    }

上面我们添加了FileLogAdapter 类,DatabaseLogAdapter类,继承了FileLog,DatabaseLog, ILogTarget接口,重写Write方法里面调用新的写日志的方式WriteLog,使用这样的方式进行了迁移变化。下面使用对象适配:

    /// <summary>
    /// 对象适配,继承ILogTarget,里面有LogAdaptee抽象日志类对象。
    /// </summary>
    public class LogAdapter:ILogTarget
    {
        /// <summary>
        ///  抽象写日志类
        /// </summary>
        private LogAdaptee _adaptee;

        public LogAdapter(LogAdaptee adaptee)
        {
            this._adaptee = adaptee;
        }

        public void Write(string info)
        {
            _adaptee.WriteLog(info);
        }
    }
在程序中的调用:

  /// <summary>
    /// 对象适配器模式(Adapter Pattern)
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            ILogTarget dbLog = new LogAdapter(new DatabaseLog());
            dbLog.Write("程序启动成功");
            ILogTarget fileLog = new LogAdapter(new FileLog());
            fileLog.Write("程序启动成功");
        }
    }

比较两者的迁移变化,在类适配方式中,我们得到的适配器类DatabaseLogAdapter和FileLogAdapter具有它所继承的父类的所有的行为,同时也具有接口ILogTarget的所有行为,这样其实是违背了面向对象设计原则中的类的单一职责原则,而对象适配器则更符合面向对象的精神,所以在实际应用中不太推荐类适配这种方式。假设我们要适配出来的类在记录日志时同时写入文件和数据库,那么用对象适配器我们会这样去写:

    /// <summary>
    /// 对象适配,继承ILogTarget,里面有LogAdaptee抽象日志类对象。
    /// </summary>
    public class LogAdapter:ILogTarget
    {
        /// <summary>
        ///  抽象写日志类
        /// </summary>
        private LogAdaptee _adapteed;

        /// <summary>
        ///  抽象写日志类
        /// </summary>
        private LogAdaptee _adapteef;

        public LogAdapter(LogAdaptee adapteed, LogAdaptee adapteef)
        {
            this._adapteed = adapteed;
            this._adapteef = adapteef;
        }

        public void Write(string info)
        {
            _adapteed.WriteLog(info);
            _adapteef.WriteLog(info);
        }
    }
调用:

 /// <summary>
    /// 对象适配器模式(Adapter Pattern)
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //同时写日志到文件和数据库
            ILogTarget dbLog = new LogAdapter(new FileLog(), new DatabaseLog());
            dbLog.Write("程序启动成功");
        }
    }
如果改用类适配器:我们难道使用这样的写法达到目的吗?

    public class DatabaseLogAdapter : DatabaseLog, FileLog, ILogTarget
    {
        public void Write(string info)
        {
            this.WriteLog(info);
        }
    }

结果肯定是不能的,一个类不能具有多个基类,这样写明细有错误。所有针对不同的情况,我们应该采用合适的方式去进行适配调度。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值