java基础_设计模式_设计基础(小鸭子游戏)

小鸭子游戏,是好多爱好者接触设计模式、认知设计模式概念的一个入门。
每个初学者的理解不同,我加上自己的理解大体是这样的:前提是处理大规模时,假设池塘中有10000头小鸭子,有红头鸭,野鸭子,木头鸭子等等,会叫会游泳,肯定是定义一个父类Duck,拥有这样的基本行为属性;现在要求鸭子中400头,可以飞,该怎么做?
有句话叫:当你处理大规模时,一定要写抽象层次编程

问题:400只小鸭子可以飞,怎么做?

1.最直接想到的就是 父类中定义fly()方法,全部的子鸭子去重写,要飞的就子类自己实现飞这个行为,不要飞的子类可以空实现。目的实现了,存在的问题:①全部子类都要改代码  ②实现的fly方法 具体实现无论是不是空,都要在栈中保留方法的引用 而维护方法的指针需要成本尤其是大量时。  基于这两点肯定不合适。

总结:通过继承实现在父类中声明的行为,主要有以下缺点:

the followings are the disadvantages of using inheritance to provide Duck behavior

①Code is duplicated across subclasses (代码在多个子类中重复)

② Runtime behavior changes are difficult (运行时行为不易改变)

③Changes can unintentionally affect other ducks (改变会牵一发而动全身,造成部分子类型不想要的改变)


2.定义一个FlyAble接口,然后定义400只需要飞的小鸭子实现这个接口,然后实现自己的方法,有没有发现问题的所在,需要每一个子类都去实现这个接口,然后写一样的fly代码;代码如下:

public interface Flyable {
    void fly();
}
public class RedHeadDuck extends Duck implements Flyable {
    @Override
    void display() {
        System.out.println("红头的");
    }

    @Override
    public void fly() {
        System.out.println("要飞的");
    }
}

图示:



这就是“java的接口不具有实现代码,实现接口无法达到代码的复用”,也就意味着“当你需要修改某个行为,你需要往下追踪,并修改每一个定义了此行为的类。” 这两句话,可以细细体会,就是接口不具有代码的实现,无法达到代码的复用。

实现Flyable接口的方式到底有什么坏处?
假设400个鸭子要能飞,那要400个鸭子实现这个接口,每个都重写400次fly方法,然后定义飞的行为,要是不同的鸭子有了高高飞,擦地飞,旋转着飞,是不是,每个鸭子要写不同的飞方法,比如

a   =》高高飞

b   =》擦地飞
c   =》旋转着飞

现在d e f g 也要旋转飞 那肯定要每一个都写旋转飞的方法  这属于“接口不具有实现代码,所以实现接口无法达到代码的复用”。


如果有专门的高高飞行为类,擦地飞行为类,旋转着飞行为类,都去实现flybehavior行为接口,重写fly表达行为,那每次用的时候,就不用写这么多重复的代码了。 而且当你想修改方法的时候只需要改一处就好了。

可以试想,将变化的内容定义形成接口可以实现变化内容和不变内容的剥离。 其接口的实现类可以实现变化内容的重用,即理解为

这些实现类并非Duck.java的子类型,而是专门的一组实现类,称之为 行为类。由行为类而不是Duck.java的子类型实现接口。这样才能保证变化的行为独立于不变的内容。

代码如下:

public interface FlyBehavior {
    void fly();
}

//具体的行为类 用翅膀飞

public class FlyWithWings implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("==带翅膀飞");
    }
}



/**
 * 父类
 */
public abstract class Duck {

    FlyBehavior flyBehavior;
   
    String color;
    int age;

    public void performFly() {
        flyBehavior.fly();
    }

    void performSwim() {
        System.out.println("==所有的鸭子都会游泳呢");
    }
}

/**
 * 红头鸭
 */

public class RedheadDuck extends Duck {
    public RedheadDuck() {
        flyBehavior = new FlyWithWings();
    }
}


测试类:

/**
 * 测试类
 */

public class TestDuck {
    public static void main(String[] args) {
        System.out.println("=============红头鸭子=========");
        showRedHeadDuck();
    }

     private static void showRedHeadDuck() {
        Duck duck = new RedheadDuck();
        duck.performFly();
      }
}
 这样就实现了鸭子类和fly这一行为的分离,两着没有了关系。

以前的做法是:行为是继承自Duck超类的具体实现而来,或者实现某个接口并由子类自行实现而来。 这两种方法都是依赖于实现。我们被实现绑的死死的,没有办法更改行为(除非写更多的代码)

这种方法和继承的不同之处在于,小鸭子的行为不是继承而来,而是和适当的行为对象结合。这是一个很重要的技巧,其实使用了策略模式中的第三个设计原则,多用组合 少用继承。

当你处理大规模时 一定要写抽象层次编程。

整个过程就是从is-a转成has-a。






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值