第一天 - 封装变化

不打扰是莪最后的温柔 提交于 2019-12-04 11:49:40

在进行类设计时,更多时候我们习惯于针对属性和方法来设计,我们会先找出类的共有属性和方法,然后用子类来扩展和区分不同类型的属性和 行为。比如一款飞车游戏,有不同的车,我们的第一反应会是建立一个 Car 的超类,然后定义车的共有属性,最后使用子类继承扩展出不同类型的车,代码的如下

public class Car {
    String name;   //名字颜色
    Integer speed; //速度
    String driveType; //驱动方式

    //如何移动
    public void move(){

    }
}

class Truck extends Car{

    public Truck() {
    }

    public Truck(Integer speed, String driveType){
        this.speed = speed;
        this.driveType = driveType;
    }

    @Override
    public void move() {
        System.out.println("卡车的驱动方式是" + driveType + "以" + speed + "速度行驶");
    }
}

 

一般来说这种设计并没有问题,不同车可以根据需要定义不同的行驶方式。但是车的类型会不断的增多,与行驶相关的属性会变多, move方法也可能需要更多的信息。

比如后期游戏为了更加符合现实,需要添加每公里耗油量。按照以上的设计,就需要在Car 类中添加 耗油量属性, 然后每个已经实现的子类都必须要修改move方法,添加上耗油量。

在上面的情境下,使用继承扩展车的类型显然很麻烦,使用接口也会面对一样的问题,一旦move 方法需要添加新的属性,所有的已经实现类必须要修改源码。为了解决这种扩展性差的问题,我们可以把可能变化的部分封装起来。

//将行驶方法设计成接口
public interface Moveable {
    void move();
}

//每个车具体的行驶方式和设计的属性使用具体的类定义
public class TrunkMoveable implements Moveable{
    Integer speed; //速度
    String driveType; //驱动方式

    public TrunkMoveable(Integer speed, String driveType) {
        this.speed = speed;
        this.driveType = driveType;
    }

    @Override
    public void move() {
        System.out.println("卡车的驱动方式是" + driveType + "以" + speed + "速度行驶");
    }
}


public class Car {
    String name;   //名字颜色

    //行驶方动态的传递进来
    public void move(Moveable moveable){
        moveable.move();
    }
}

class Truck extends Car{

}

  

以上就是将类中会变化的部分封装起来,Car 的 move 方法接收一个 Moveable 类,在运行时根据需要传递进去
这种设计方式有几个好处
1、无论以后行驶方式如何变化,我们的关注点只是 TrunkMoveable 这种具体实现类
2、当move 方式需要变化时,我们可以不必修改源码,可以重新写一个Moveable 实现类,使用时传递新的实现类即可
3、Moveable还可以设计一个超类实现,Moveable 相关属性可以放在超类中,代码更简单,处理一起统一修改也更方便

当然这种设计也有坏处
1、类的数量比原来多了一倍,后期如果有修改,同一类型的 Moveable 会有多个实现,引起类爆炸,管理起来比较麻烦
2、将行驶方式定义成一个类比较别扭
3、车的部分会被分散,与普通设计不同,理解成本更高

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!