`

《深入浅出设计模式-中文版》读书笔记 策略模式(二)

阅读更多

  接着上回的“针对接口编程,不针对实现编程”原则说。

  假设开始我们设计了一个鸭子基类,发声、游泳和显示外观是鸭子类的功能。发声和游泳是通用的方法,放在基类实现,显示外观由于鸭子的不同而不同,放在继承类实现。可以设计出下面的类结构。

  

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> public abstract class DuckBase
    {
        
public virtual void Quack()
        {
            Console.WriteLine(
"我会嘎嘎叫");
        }
        
public virtual void Swin()
        {
            Console.WriteLine(
"我会游泳");
        }
        
public abstract void Display();

    }
    
public class GreenHeadDuck : DuckBase
    {
        
public override void Display()
        {
            Console.WriteLine(
"我是绿头鸭子");
        }
    }
    
public class RedHeadDuck : DuckBase
    {
        
public override void Display()
        {
            Console.WriteLine(
"我是红头鸭子");
        }
    }

 

  看起来还是比较OO的,利用了继承,复用了游泳和发声的代码。可是突然有一天需要创新,提出鸭子也应该可以飞,有人就提出来“这还不简单,在基类上加一个方法,鸭子都会飞了”。

  

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->public abstract class DuckBase
    {
        
public virtual void Quack()
        {
            Console.WriteLine(
"我会嘎嘎叫");
        }
        
public virtual void Swin()
        {
            Console.WriteLine(
"我会游泳");
        }
        
public abstract void Display();

        
public virtual void Fly()
        {
            Console.WriteLine(
"我是鸭子,我会飞");
        }
    }

 

 

  貌似解决了鸭子会飞的问题。可是有一天问题来了,橡皮鸭子怎么会飞呢?它没有生命啊?

  怎么回事呢?就是由于我们在基类添加的实现方法,继承类继承了这个方法,所有各种类型的鸭子都会飞了。可是还是有一些是不应该飞的,就像橡皮鸭子,木头鸭子等等。看来为了复用“飞”,而使用继承,结局并不理想。

  当然了,也有解决的办法。既然是基类的方法,我们可以在继承类中重写它,如果不会飞就什么都不做?发声也出现了类似问题,不是每种鸭子都“嘎嘎”叫的,有的是“吱吱”发声,好吧,重写发声方法,以前的呢?都检查一遍,以后的新类型鸭子也需要注意叫声和是否会飞,好像有点麻烦?

  

 

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> public class RubberDuck : DuckBase
    {
        
public override void Display()
        {
            Console.WriteLine(
"我是橡皮鸭子");
        }
        
public override void Quack()
        {
            Console.WriteLine(
"我会咯吱咯吱叫");
        }
        
public override void Fly()
        {
            Console.WriteLine(
"我不会飞");
        }
    }

 

  这样的继承造成了以下几个问题:

  •   飞和叫的代码在多个子类中重复
  •   运行的时候,行为不容易改变
  •   很难知道鸭子的所有行为
  •   改变牵一发,而动全身,其他类型的鸭子平白无故的多了一些不需要的功能。如果确实不要还要修改其他类型鸭子的代码。

  有人又提出来了,利用接口吧。将会飞和发声写两个接口,然鸭子类去实现,实现了接口的就具有了这两个功能,没有实现的就不受影响。

  

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> public abstract class DuckBase
    {

        
public virtual void Swin()
        {
            Console.WriteLine(
"我会游泳");
        }
        
public abstract void Display();

      
    }
    
public class GreenHeadDuck : DuckBase,IFlyBehavior,IQuackBehavior
    {
        
public override void Display()
        {
            Console.WriteLine(
"我是绿头鸭子");
        }

        
public void Fly()
        {
            
throw new NotImplementedException();
        }

        
public void Quack()
        {
            
throw new NotImplementedException();
        }
    }
    
public class RedHeadDuck : DuckBase, IFlyBehavior, IQuackBehavior
    {
        
public override void Display()
        {
            Console.WriteLine(
"我是红头鸭子");
        }

        
public void Quack()
        {
            
throw new NotImplementedException();
        }

        
public void Fly()
        {
            
throw new NotImplementedException();
        }
    }
    
public class RubberDuck : DuckBase
    {
        
public override void Display()
        {
            Console.WriteLine(
"我是橡皮鸭子");
        }
        
public override void Quack()
        {
            Console.WriteLine(
"我会咯吱咯吱叫");
        }
          }

    
public interface IFlyBehavior
    {
        
void Fly();
    }
   
  
    
public interface IQuackBehavior
    {
        
void Quack();
    }

 

  这样还是有点问题。就是很是很多的鸭子都会飞的,都会叫的,这部分的鸭子的飞和叫的代码就会重复,而且以前现有鸭子都需要检查一遍,都可能需要修改。接口虽然解决了只有继承才会具有相应的功能,但是因为接口没有实现,只有方法体的定义,所以造成了代码没有得到复用。表面看起来这两者好像是矛盾的。

  引出另外一个设计原则:

  找出应用中可能需要变化的地方,把他们独立出来,不要和那些不需要变化的代码混合在一起。把会变化的代码“封装”起来,好让修改的时候不影响其他部分。使得代码的修改对系统的影响最小,使得系统更具有弹性。

  也就是说每次有新的需求,都会造成一部分代码的变化,将这部分变化的代码抽象出来,保持其他代码的稳定性。让系统的某部分修改不影响其他部分,这样其他部分就不需要测试,否则就需要全部测试一遍才可以保证代码的修改是正确的。

  上面这个列子中的飞和叫是变化的地方,其他的没有太大变化。飞也有很多种方式,叫也有很多种“声音”。这两种叫做“行为”更好。原来的鸭子类,这两种行为是写死的,能否在初始化鸭子的时候,自己指定行为的方式呢?可以,开放一个属性,或者是一个方法,可以设置定义在鸭子基类中的行为就可以了,或者在构造函数中添加参数,指定行为。

  

 

代码
<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeautyCode.DesignPattern.Head.First
{
    public abstract class DuckBase1
    {
        private IFlyBehavior1 _flyBehavior;

        public IFlyBehavior1 FlyBehavior
        {
            get { return _flyBehavior; }
            set { _flyBehavior = value; }
        }
        private IQuackBehavior1 _quackBehavior;

        public IQuackBehavior1 QuackBehavior
        {
            get { return _quackBehavior; }
            set { _quackBehavior = value; }
        }
        public virtual void Swin()
        {
            Console.WriteLine("我会游泳");
        }
        public void PerformQuack()
        {
            _quackBehavior.Quack();
        }
        public void PerformFly()
        {
            _flyBehavior.Fly();
        }
       
        public abstract void Display();
    }
    public class GreenHeadDuck1 : DuckBase1
    {
        public override void Display()
        {
            Console.WriteLine("我是绿头鸭子");
        }
    }
    public class RedHeadDuck1 : DuckBase1
    {
        public override void Display()
        {
            Console.WriteLine("我是红头鸭子");
        }
    }
    public class RubberDuck1 : DuckBase1
    {
        public override void Display()
        {
            Console.WriteLine("我是橡皮鸭子");
        }
      
    }
    public interface IFlyBehavior1
    {
          void Fly();
    }
    public class FlyWithWings : IFlyBehavior1
    {
        public void Fly()
        {
            Console.WriteLine("有翅膀飞了");
        }
    }
    public class FlyNoWay : IFlyBehavior1
    {
        public void Fly()
        {
            Console.WriteLine("没有也飞了");
        }
    }
    public interface IQuackBehavior1
    {
          void Quack();
    }
    public class QuackA : IQuackBehavior1
    {
        public void Quack()
        {
            Console.WriteLine("嘎嘎");
        }
    }
    public class Squeak : IQuackBehavior1
    {
        public void Quack()
        {
            Console.WriteLine("吱吱");
        }
    }
    public class MuteQuack : IQuackBehavior1
    {
        public void Quack()
        {
            Console.WriteLine("哇哇");
        }
    }

}


 

  调用代码

  

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> Head.First.DuckBase1 duck = new Head.First.GreenHeadDuck1();
            duck.FlyBehavior 
= new Head.First.FlyWithWings();
            duck.PerformFly();

  如果增加新的飞行方式,也只需要添加一个飞接口的实现,然后调用代码的duck.FlyBehavior = new Head.First.FlyWithWings();这一句进行修改就可以了,指定到新实现上面,具有了新的飞行方式。

分享到:
评论

相关推荐

    设计模式+UML.rar

    包含以下文件: Java设计模式-图解-附代码.pdf 从Java类库看设计模式.doc 六大UML类图关系.docx 认识UML类图元素_java之UML.doc 设计模式6大原则.doc 设计模式学习笔记.doc 深入浅出设计模式(中文版).pdf

    Java设计模式教程

    该资料介绍Java各类开发模式,包含以下教程:《深入浅出设计模式(中文版)》《Java单例模式》《Java设计模式-图解-附代码》《JAVA设计模式之单例模式(完整版)》《Java学习笔记(必看经典)》《Java总复习》《单例模式》...

    Head First 设计模式 扫描版

    这本书以其独特的视觉风格和易于理解的教学方法,深入浅出地介绍了设计模式这一复杂的主题。设计模式是软件工程中经过实践验证的解决方案,用于解决在面向对象设计中常见的问题。 本书包含23种经典的设计模式,这些...

    Java设计模式第2版中文版.rar

    总之,《Java设计模式第2版中文版》是一本涵盖全面、深入浅出的教程,无论是初学者还是经验丰富的开发者,都能从中受益。通过学习这本书,你可以提升自己的编程思维,写出更优雅、更健壮的代码,为团队协作和项目...

    <<MFC深入浅出>>(中文简体)

    "读书拉.htm"可能是书中的一些笔记或阅读指南,"深入浅出 MFC_华中理 工_简体版.pdf"是主要的教材内容,"dushula.txt"可能是读者在阅读过程中的个人感悟或摘录,这些资源结合起来,将构成一个全面的MFC学习资料库。...

    包括JAVA夜未眠,thinkingJAVA和学习笔记

    这本书以其深入浅出的讲解方式,详尽地介绍了Java语言的各个方面。它不仅包含基本语法,还涉及设计模式、泛型、并发编程等高级话题,是进阶Java开发者的必读之作。中文版的提供使得中文读者能够无障碍地学习这本权威...

    vc源代码合集0951.rar

    2012-06-12 11:55 3,721,136 VC++动态链接库(dll)编程深入浅出.rar 2012-06-12 13:02 23,185 VC++图像平滑处理+程序.rar 2012-06-12 12:12 45,056 VC++操作INI配置文件的实现.doc 2012-06-12 11:48 11,728,284 VC++...

    Programming in Go-带书签目录超清文字版.pdf

    这本书深入浅出地介绍了Go语言的设计理念、语法特性和实际应用,旨在帮助读者快速掌握Go语言并能进行高效的编程实践。 Go语言,由Google公司的Robert Griesemer、Rob Pike及Ken Thompson等人设计开发,于2009年公开...

    《Effective C++(中文版)》

    通过以上概述,我们可以看到《Effective C++(中文版)》不仅是一本技术手册,更是一部深入浅出地介绍C++编程精髓的作品。无论是初学者还是有一定经验的开发者,都能从中受益匪浅。阅读这本书不仅可以帮助我们提高...

    Head First Servlet JSP(中文版)

    这本书以易理解的图文并茂的形式,深入浅出地讲解了这两个重要技术。 Servlet是Java编程语言中的一个接口,用于扩展服务器的功能,特别是Web服务器。它允许程序员创建动态、交互式的HTTP服务。Servlet可以处理...

    javaee经典学习资料大全

    - JavaEE进阶之Spring事务深入浅出:虽然Spring是Java EE的一个补充框架,但它的事务管理部分在企业级应用中非常重要,值得深入学习。 - J2EEWeb应用开发技术教材:Web层的开发是Java EE应用中的关键部分,学习如何...

    原版think in java4

    这本书以其深入浅出的讲解方式和全面的内容覆盖,成为了学习Java语言的重要参考书籍。中文版的出现使得更多的中国读者能够无障碍地理解和掌握Java编程精髓。 在描述中提到,“非扫描”意味着这是一份正式授权的电子...

    Java并发编程实战(中文版).rar

    总的来说,《Java并发编程实战》中文版是一本深入浅出的并发编程指南,无论你是初学者还是经验丰富的开发者,都能从中获得宝贵的知识和启示。通过学习书中的内容,你将具备驾驭Java并发编程的能力,写出更健壮、高效...

    android开发资料大全

    《深入浅出Android--Google手持设备应用程序设计》下载 《Android编程指南》android-book.pdf 下载 《Android应用开发揭秘》PDF高清版下载 游戏项目分享——忍者突袭 只发精品——分享一个短信应用源码 百度地图...

    重构_改善既有代码的设计.rar

    8. **侯捷译本**:侯捷是中国知名的软件技术专家,他的翻译风格深入浅出,使得原书的概念和方法论更加贴近中文读者的理解。 9. **超星版**:超星版通常指的是电子版,可能包含了一些电子阅读特有的标记或格式,方便...

    完整版大话练法.rar

    “大话”在中文里通常用来形容深入浅出地讲述复杂话题,这里的“大话练法”可能是作者以轻松幽默的方式讨论编程技巧和职业发展路径的一种方式。在IT行业,不断学习和提升技能是每个从业者必须面对的挑战,而这本书很...

    ext JS 源码和学习资料

    2. Ext2.2API中文版(最终完成版).CHM:此文档为EXT JS 2.2版本的中文API,虽然版本较旧,但对于理解EXT JS早期版本的开发模式和组件结构仍然有参考价值。 三、EXT JS 实用教程与开发指南 1. EXT_JS实用教程.doc:...

    51CTO下载-【android资料免豆下载】汇总大量教程+工具+源码下载地址.pdf

    4. Android 深入浅出:包括 Android 的设计模式、架构设计、性能优化、安全机制等高级技术。 5. Android 开发入门与实践:涵盖 Android 开发的基础知识和实践操作,包括 Android Studio 的使用、 Android 项目结构...

Global site tag (gtag.js) - Google Analytics