zoukankan      html  css  js  c++  java
  • 设计模式(6)适配器模式

    模式介绍

    适配器模式用于协调两个不兼容的接口之间的差异。 当用于无法重构的接口时(例如,当接口由Web服务或API控制时),此模式特别有用。

    示例

    假设我们在维护肉类安全烹饪温度数据库,旧的系统是这样维护的:

    public enum TemperatureType
    {
        Fahrenheit,//华氏摄氏度
        Celsius//摄氏度
    }
    
    /// <summary>
    /// The legacy API which must be converted to the new structure
    /// </summary>
    class MeatDatabase
    {
        // Temps from http://www.foodsafety.gov/keep/charts/mintemp.html
        public float GetSafeCookTemp(string meat, TemperatureType tempType)
        {
            if (tempType == TemperatureType.Fahrenheit)
            {
                switch (meat)
                {
                    case "beef":
                    case "pork":
                        return 145f;
    
                    case "chicken":
                    case "turkey":
                        return 165f;
    
                    default:
                        return 165f;
                }
            }
            else
            {
                switch (meat)
                {
                    case "beef":
                    case "veal":
                    case "pork":
                        return 63f;
    
                    case "chicken":
                    case "turkey":
                        return 74f;
    
                    default:
                        return 74f;
                }
            }
        }
    
        //每盎司(28.3495231克)包含的卡路里
        public int GetCaloriesPerOunce(string meat)
        {
            switch (meat.ToLower())
            {
                case "beef": return 71;
                case "pork": return 69;
                case "chicken": return 66;
                case "turkey": return 38; //Wow, turkey is lean!
                default: return 0;
            }
        }
    
         //每盎司(28.3495231克)包含的蛋白质
        public double GetProteinPerOunce(string meat)
        {
            switch (meat.ToLower())
            {
                case "beef": return 7.33f;
                case "pork": return 7.67f;
                case "chicken": return 8.57f;
                case "turkey": return 8.5f;
                default: return 0d;
            }
        }
    }
    

    可以看到,这个遗留系统没有使用面向对象模式开发,上面的那些数据应该是Meat类的属性。

    我们创建一个Meat类:

    /// <summary>
    /// The new Meat class, which represents details about a particular kind of meat.
    /// </summary>
    class Meat
    {
        protected string MeatName;
        protected float SafeCookTempFahrenheit;
        protected float SafeCookTempCelsius;
        protected double CaloriesPerOunce;
        protected double ProteinPerOunce;
    
        // Constructor
        public Meat(string meat)
        {
            this.MeatName = meat;
        }
    
        public virtual void LoadData()
        {
            Console.WriteLine("
    Meat: {0} ------ ", MeatName);
        }
    }
    

    现在的问题是,我们无法修改旧系统的API。我们需要另一个继承自Meat的类但保留对API的引用,以便API的数据可以加载到Meat类的实例中:

    /// <summary>
    /// The Adapter class, which wraps the Meat class and initializes that class's values.
    /// </summary>
    class MeatDetails : Meat
    {
        private MeatDatabase _meatDatabase;
    
        // Constructor
        public MeatDetails(string name)
            : base(name)
        {
        }
    
        public override void LoadData()
        {
            // The Adaptee
            _meatDatabase = new MeatDatabase();
    
            SafeCookTempFahrenheit = _meatDatabase.GetSafeCookTemp(MeatName, TemperatureType.Fahrenheit);
            SafeCookTempCelsius = _meatDatabase.GetSafeCookTemp(MeatName, TemperatureType.Celsius);
            CaloriesPerOunce = _meatDatabase.GetCaloriesPerOunce(MeatName);
            ProteinPerOunce = _meatDatabase.GetProteinPerOunce(MeatName);
    
            base.LoadData();
            Console.WriteLine(" Safe Cook Temp (F): {0}", SafeCookTempFahrenheit);
            Console.WriteLine(" Safe Cook Temp (C): {0}", SafeCookTempCelsius);
            Console.WriteLine(" Calories per Ounce: {0}", CaloriesPerOunce);
            Console.WriteLine(" Protein per Ounce: {0}", ProteinPerOunce);
        }
    }
    

    最后,我们在客户端调用:

    static void Main(string[] args)
    {
        //Non-adapted
        Meat unknown = new Meat("Beef");
        unknown.LoadData();
    
        //Adapted
        MeatDetails beef = new MeatDetails("Beef");
        beef.LoadData();
    
        MeatDetails turkey = new MeatDetails("Turkey");
        turkey.LoadData();
    
        MeatDetails chicken = new MeatDetails("Chicken");
        chicken.LoadData();
    
        Console.ReadKey();
    }
    

    总结

    适配器模式尝试协调两个不兼容的接口,并且在无法重构其中一个或两个接口时特别有用。

    该模式和外观模式特别相似,但是用途却不同。简单来说,
    外观模式相当于说“这永远不会奏效,我会建立自己的。” 适配器模式相当于说“当然它可以工作,只需要稍微调整一下。”

    源代码

    https://github.com/exceptionnotfound/DesignPatterns/tree/master/Adapter

    原文

    https://www.exceptionnotfound.net/the-daily-design-pattern-adapter/

  • 相关阅读:
    持续集成系统敏捷开发的基石
    云计算对IT产业的影响
    类封装的驱动程序
    竹林蹊径:深入浅出Windows驱动开发
    云计算的SPI服务模型
    什么是云计算
    多态
    我们需要什么样的计算
    电子工业的发展也带动了电子设计自动化技术
    云计算的部署模型
  • 原文地址:https://www.cnblogs.com/talentzemin/p/9828573.html
Copyright © 2011-2022 走看看