The car models with design strategy pattern

Xiaoqiang where the game company recently designed a racing game in which there are multiple models, such as bicycles, tricycles, cars, trucks, sports cars and so on. Based on object-oriented design ideas, and John designed a car superclass, and make a variety of vehicles to inherit the superclass. Because it is a new game, to see the market reaction, so the first version of all types of vehicles only different styles, other features are the same:

After on-line, user reaction is not bad. So the company decided to vigorously promote the game, more features designed to attract players to join. So, Johnny received a new task, in addition to the different style, so that all vehicles need to accelerate. This is not simple it, based on the original design, while both the code reusability, and John quickly developed this feature:

Added a parent class Vehicle accelerate () method to accelerate, so that all vehicles will be able to accelerate up. Meanwhile, in order to allow non-motorized bicycle can not accelerate, in the non-motor-related subclass covers accelerate the parent class () method, this method is invoked when a user, prompts the user to type the vehicle is not accelerating.

After functional development, and John was very happy, this design is simply fantastic, vehicle type of vehicle can accelerate inherit the parent class () method directly, to avoid writing a lot of duplicate code, rather than a vehicle type of vehicle only we need to override the parent class method on the line, although the trouble spots, but perhaps also non-motor vehicle acceleration after it, can be changed in it, ah, pay more than what they say is ......

But in a Code Review Conference, the development team leader raises a question: If in the future more and more non-motor vehicles, each will need a new covered accelerate the parent class () method is not too much trouble. And, if in the future there are more vehicles rather than vehicles have no method of (for example: the vehicle plus gasoline), are by this design, add a non-motorized methods and what does not need to cover a lot of that It was a disaster.

It seems, this design does still flawed. After the meeting, Johnny thought about it: because the above question is a motor vehicle Vehicle category encompasses a method, but this method is not suitable for non-motorized vehicles. That is not a subclass of these objects, part of some abstract no way out, not on the Vehicle in, but on the other one a single structure, so that the selection of the various types of vehicles inherited or achieved not on the list .

说干就干,小强很快又设计出了一个版本。因为Java不能多重继承,所以,使用接口来放这些方法,子类按需实现即可:

这么设计解决了上面提到的问题,自行车等非机动车不再需要维护一个本不该自己维护的方法,而汽车、卡车等车辆按需继承AccelerateAble接口,在自己的类中实现具体的加速方法。嗯,按需分配,各得其所,就这么搞。

可当小强动手敲代码时就犯起了嘀咕,他发现虽然非机动车不再需要继承accelerate()方法了,可是每一个机动车却需要了。而且因为加速方法的实现都是一样的,却在机动车类型的车辆中各自都要复制一份,代码可复用性太差了。而最最无法接受的是,将来要是要修改这个accelerate()方法,每一个机动车实现类都要修改一遍,这还不如之前的设计呢……

细心的组长发现了正在焦头烂额的小强,再看看他的新设计,笑着说:“其实,你这个新的设计方案虽然不可行,但是已经有一点对的思路了。你能意识到把应用中可能变化的东西提取封装起来,好让其他部分不再受到影响这点很好,可是实现上需要一些改动:如果把accelerate的实现也抽象出来你看怎么样?”。

把实现也抽象出来?那要怎么弄呢?想想看,抽象出来的东西会是这样:

怎么让机动车和非机动车获取到这些实现呢?还是实现AccelerateBehavior接口明显不对,因为接口的具体实现已经有了。不用实现的话,那该怎么办呢?对了!用组合的方式。嗯~is a不行就用has a试试。而基于最开始的设计,由于各类型车辆都继承自Vehicle父类,将AccelerateBehavior作为一个成员变量放入Vehicle类中再好不过了。经过一番折腾,小强终于写出了自己满意的方案:

通过上面的修改,解决了之前遇到的两个问题,非机动车可以不再需要维护自己不需要的accelerate()方法;同时,机动车也可以复用父类给予的机动车加速方法,而具体使用的时候,在构造方法中构建具体的accelerateBehavior属性就可以啦,代码类似这样:


class Bicycle extents Vehicle{
    public Bicycle(){
      this.accelerateBehavior = new NoAccelerate();
    }
    void style(){
      //自行车装饰
    }
}
class Car extents Vehicle{
    public Car(){
      this.accelerateBehavior = new CarAccelerate();
    }
    void style(){
      //小汽车装饰
    }
}
public static void main(){
  Vehicle bicycle = new Bicycle();
  bicycle.performAccelerate();
  Vehicle car = new Car();
  car.performAccelerate();
}

不知道大家有没有发现,上面的设计还有一个好处就是,以后如果各种车辆的加速方法不一样的话,只需要设计不同的加速方法实现类实现AccelerateBehavior接口,而在具体的车辆构造方法中构造具体的加速属性就可以啦。而且,如果之后还想要搞出一个时而可以加速,时而不能加速的车子(比如小汽车没油了),那么我们可以添加set方法对accelerateBehavior成员变量进行设置,实现动态设置是否可加速。啧啧啧,太棒了!!!


class Car extents Vehicle{
  public Car(){
    this.accelerateBehavior = new CarAccelerate();
  }
  void style(){
    //小汽车装饰
  }
  public void setAcclerateBehavior(AcclearteBehavior acc){
    this.acclerateBehavior = acc;
  }
}

拿着最新的设计方案,组长对小强赞许了一番。这个设计:

  • 将应用中变化的地方抽取封装出来,不和不变的代码混在一起;

  • 针对接口(抽象)编程,代码更易于维护,可扩展性也更好;

  • 通过组合而非继承的方式,代码可扩展性更大;

没错,其实上面的这个设计,就是我们要提到的第一个设计模式--策略模式的设计思路:通过抽象封装出算法族,让它们之间可以相互替换,此模式让算法的变化独立于使用算法的用户,用户无需关心算法的具体实现,是要设置好,用就行了。

当然强哥这里只是提了设计的思路,而具体如何使用,如果大家还是一头雾水的话,强哥在今天的第二篇推文中,也转了一篇比较简单易懂的策略模式的具体使用,有兴趣的大家可以看看。

本文编写主要参考自:《Head First设计模式》一书,有兴趣的可以买这本书看看哦,真的是一本极力推荐的书!!!

关注公众号获取更多内容,有问题也可在公众号提问哦:

强哥叨逼叨

叨逼叨编程、互联网的见解和新鲜事

 

发布了54 篇原创文章 · 获赞 69 · 访问量 25万+

Guess you like

Origin blog.csdn.net/seanxwq/article/details/102961724