• Head First 设计模式--1策略模式 组合优于继承


    策略模式:第一了算法族,分别封装起来,让他们之间可以互相替换,次模式让算法的变化独立于使用算法的客户。

    首先看个错误的面向对象。

    假如我们需要写一个关于鸭子的程序,各种类型的鸭子。第一想到的就是建一个Duck接口,然后各种鸭子实现这个接口。

    interface Duck{
      public void quack();
    }
    
    class MiniDuck implements Duck{
      @Override
      public void quack() {
        //........
      }
    }

    但是如果突然有一天,有个新需求,要有一个会飞的鸭子。那么炸了,在Duck上添加一个fly方法,所有的实现类都需要重写这个方法,如果真的有这个耐心把所有的类上都添加了一个新的方法,但是之前的测试你还需要重新一个一个的测试。确定要这么干。这时也许会想到另外一个方法,不在Duck上添加,只需要在会飞的那类鸭子中添加一个方法。如果你这么想,当初设计这个Duck接口干什么。直接写每个类啊,如果真的就这么干了,假如某个某个方法中,传入的参数只需要一个鸭子,不管什么类型的鸭子。要怎么处理。。。

    经过上面这么一想,Duck是一定要有的,这时的想法会是在创建两个接口,一个Flyable接口,一个Quackable接口,这两个接口分别有fly和quack方法,Duck中有自己的方法。如果这么弄,那么每个鸭子首先要实现Duck接口,其次,根据具体功能在判断需不需要集成另外两个接口。你感觉这样真的好?如果感觉还可以接受,突然有一天,大多数的鸭子又有了一个查看颜色的方法。你需要在写第三个接口来让实现类鸭子实现。40个类同时实现这个接口,想一想工作量。

    设计原则:找到应用中可能要变化之处,把他们独立出来,不要和那些不变的代码混在一起。

    这里我们知道鸭子的飞和叫是变化的,就把这两部分抽出来,让他们远离鸭子类。设计两组类处理飞和叫。

    设计原则:针对接口编程而不是针对实现编程。(这里所说的针对接口编程指的是针对超类,关键在于利用多态,接口并不一定是interface,可以在没有interface的情况下“针对接口编程”,只是一般来说我们用interface和abstract来当超类)

    我们利用接口来代表每个行为,创建一个FlyBehavior和一个QuackBehavior,行为的每个实现都将实现上面的接口,而不是由Duck类来实现上面的接口。原来的时候,行为由Duck超类来实现或由子类具体实现。这两种做法都是依赖于实现。而现在的实现是在每个接口的子类,不会绑定在Duck身上。

    直接看代码

    interface FlyBehavior {
      public void fly();
    }
    
    class FlyWithWings implements FlyBehavior {
      @Override
      public void fly() {
        System.out.println("i am flying");
      }
    }
    
    class FlyNoWay implements FlyBehavior {
      @Override
      public void fly() {
        System.out.println("i can not fly");
      }
    }
    
    
    interface QuackBehabior {
      public void quack();
    }
    
    class Quack implements QuackBehabior {
      @Override
      public void quack() {
        System.out.println("Quack");
      }
    }
    
    class MuteQuack implements QuackBehabior {
      @Override
      public void quack() {
        System.out.println("<< Silence >>");
      }
    }
    
    class Squeak implements QuackBehabior {
      @Override
      public void quack() {
        System.out.println("Squeak");
      }
    }
    
    
    abstract class Duck {
      FlyBehavior flyBehavior;
      QuackBehabior quackBehabior;
    
      public void setFlyBehabior(FlyBehavior fb) {
        this.flyBehavior = fb;
      }
    
      public void setQuackBehavior(QuackBehabior qb) {
        this.quackBehabior = qb;
      }
    
      public Duck() {}
    
      public abstract void display();
    
      public void performFly() {
        flyBehavior.fly();
      }
    
      public void performQuack() {
        quackBehabior.quack();
      }
    
      public void swim() {
        System.out.println("all ducks float");
      }
    }
    
    class MallardDuck extends Duck {
      public MallardDuck() {
        quackBehabior = new Quack();
        flyBehavior = new FlyWithWings();
      }
    
      @Override
      public void display() {
        System.out.println("i am a Mallard duck");
      }
    }

    类图:

    这里Duck是不是应该也设计成接口?这个要根据自己具体的程序来定,在这个程序中,并不需要,让Duck成为一个具体类可以让继承的子类与Duck具有相同的属性和方法,比如swim方法,不用每个继承类在去重写swim方法,游泳都是一样的游泳。

    这里的设计模式就是用到的策略模式,如果想动态的设置鸭子的飞行方式,在运行时,只要设置一个对应的FlyBehavior即可。

    设计原则:多用组合,少用继承

  • 相关阅读:
    java 原子性 可见性 有序性
    java中Array/List/Map/Object与Json互相转换详解(转载)
    观察者模式(转载)
    TCP协议
    “数字签名”与“数字证书”
    两道笔试题
    定时任务处理过程中的问题
    行数据库VS列数据库
    B树和B+树
    ThreadPoolTaskExecutor介绍
  • 原文地址:https://www.cnblogs.com/badboyf/p/6184245.html
Copyright © 2020-2023  润新知