ゲーム会社は最近、このようなように自転車、三輪車、自動車、トラック、スポーツカーとなど複数のモデルがあるここでレースゲームを設計しXiaoqiang。オブジェクト指向設計のアイデアをもとに、ジョンは車のスーパークラスを設計し、スーパークラスを継承するために、車両のさまざまなを作ります。それは市場の反応を見て、新しいゲームなので、車だけで、さまざまなスタイルのすべてのタイプの最初のバージョンなので、他の機能は同じです。
上の行の後に、ユーザーの反応が悪いわけではありません。同社は積極的にゲームを促進することを決定したので、より多くのプレイヤーが参加することを誘致するために設計された機能。だから、ジョニーはすべての車両が加速する必要があるように、異なるスタイルに加えて、新しいタスクを受け取りました。コードの再利用性の両方ながらこれは、元の設計に基づいて、それは簡単ではない、とジョンはすぐにこの機能を開発しました:
すべての車両は、最大加速することができるようになりますように、加速するための親クラスの車両加速()メソッドを追加しました。一方、非原動機付自転車は、親クラス()メソッドを促進する非運動関連サブクラスカバーに、加速することができないユーザは、車両を入力するようユーザに促す場合、このメソッドが呼び出されるようにするために加速されていません。
機能開発の後、ジョンは、車両の車種ではなく車両の車種よりも、重複したコードの多くを書い避けるために、直接、親クラス()メソッドを継承加速することができ、この設計は、単に素晴らしいです、とても幸せでした唯一の我々は、ライン上の親クラスのメソッドをオーバーライドする必要があり、トラブルスポットが、それの後に、おそらく、非自動車の加速が、賃金より彼らが言うよりも、ああ、それに変更することができます......
しかし、コードレビュー会議では、開発チームのリーダーが疑問提起:将来の場合は、より多くの非自動車を、それぞれが必要とする新しい覆われた親クラスを加速()メソッドは、あまりにも面倒ではありません。そして、将来的にはより多くの車両が存在する場合ではなく、車がのない方法がありません(例:車両プラスガソリン)を、この設計によるものであり、非電動メソッドを追加し、どのようなことの多くをカバーする必要はありません。それは災害でした。
この設計はまだ不備ん、そうです。会議の後、ジョニーはそれについて考えた:上記の質問には、自動車の車両カテゴリは、方法を包含しているが、この方法は、非電動車には適していませんので。それはしていない車両に、いくつかの抽象なしの方法うちの一部、これらのオブジェクトのサブクラスではありませんが、他の1つの構造上、車の様々なタイプの選択が継承されたので、というか、リストにない達成しました。
说干就干,小强很快又设计出了一个版本。因为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设计模式》一书,有兴趣的可以买这本书看看哦,真的是一本极力推荐的书!!!
关注公众号获取更多内容,有问题也可在公众号提问哦:
强哥叨逼叨
叨逼叨编程、互联网的见解和新鲜事