OOP - 一个班级如何成为另一个班级?

uyl*_*lmz 2 java oop domain-driven-design

一个人有身份证.学生有学生证.司机有驾驶执照.

  • 一个人上学并成为学生.
  • 一名学生毕业并成为一名普通人.
  • 一个人获得驾驶执照并成为驾驶员.
  • 学生获得驾驶执照并成为驾驶员.

这些事情是否只是状态改变,如下例所示:

class Person {
    ID id;
    StudentID stId;
    DriverLicense license;

    void drive() {
        if(license == null) //illegal state exception
        //drive
    }

    //bla bla
}
Run Code Online (Sandbox Code Playgroud)

还是继承?由于对象是数据+行为,新数据和能够做新事物应该保证新对象

class Student extends Person {
    //
}

class Driver extends Person {
    //
}

//things get messy here, in Java you can't extend multiple class
//what if there's a rule that, student drivers can request/get a tax reduction?
class DriverStudent extends Person, Driver {
    //
}
Run Code Online (Sandbox Code Playgroud)

加上,更重要的是,一个人如何成为另一个?通过方法或构造函数或第三类(如服务或聚合)?

class Person {
    Driver getADriversLicense() {
        //create and return a Driver
        //this person still exists but now there's a driver with this person's data
    }
}

or:

class Driver extends Person {
    public Driver(Person p) {
        //constructor
    }
}

or:

class Aggregate {
    Driver giveDriversLicense(Person p) {
        // access internal state of both objects(ditch encapsulation) and return a driver?
        // put aggregate in same package with Driver and Person and use package private methods to provide encapsulation?
    }
}
Run Code Online (Sandbox Code Playgroud)

Gau*_*tam 5

看到这种关系的更好方法是通过角色,即一个人可以扮演多个角色.

一个人可以成为一名驾驶员和一名学生,也可能是一名员工的场景怎么样?

所以IMO最好代表如下 -

class Person{

     List<Role> currentRoles ; 

     List<Role> getCurrentRoles(){ 
         return currentRoles ; 
     }

     public void addRole(Role role){
          currentRoles.add(role) ; // so on
     }  
}
Run Code Online (Sandbox Code Playgroud)

使用泛型和类型安全转换,您可以轻松检索特定角色并在其上调用相关操作.

public interface DriverRole implements Role {

    License getDriversLicense() ;
} 
Run Code Online (Sandbox Code Playgroud)

编辑:进一步完全回答您的问题,它可以轻松解决人员获得或失去角色的情况,即添加或删除角色.正如评论中所指出的,这种关系最好通过Has <0..M>关系表示,然后是IS - 关系.

编辑1相比之下,当您使用Decorator模式时,您的原点被包装,太多的装饰器可以创建一个聚合链,IMO不是理想的场景,或者它会导致装饰器继承链不符合我的喜好.

已经说过,根据具体的情况,一个特定的模式可能比另一个更合适,但在你给出的例子中我认为角色的简单聚合是最好的.