问题描述
有如下4种角色,这些角色的属性和行为分别是
股票投资者:姓名、年龄、学炒股、说英语
基金投资者:姓名、年龄、学炒基
股票经理:姓名、年龄、教炒股、说英语
基金经理:姓名、年龄、教炒基
请用所学知识,想想设计出哪些类,哪些接口?
分析
对于初学面向对象的同志们可能会想,把这4个角色定义成4个类,分别写入他们的属性和方法,然后在测试类中创建者这4个对象,然后调用各自的方法。学过继承之后,可以抽取相同属性和方法写到一个基类里面,作为派生类的4个角色类无需再写这些属性;学过接口之后,可以把具体流程不同的行为抽取到接口中,在接口中统一一下这些行为的规范。本Reno认为当前最直观且清晰的思路如下
- 这里一共有4种角色,先定义4个类,不要着急写入成员
- 发现这些角色都有共同属性:姓名、年龄,定义一个Human类,把共同属性抽离出来写进Human类,让4种角色继承Human
- 投资者都有学习的行为,经理则有教的行为,但教和学的具体内容不一样,定义两个接口Teach和Learn把教和学的行为抽象到Teach和Learn接口中,让所有经理、投资者分别实现里面的教/学方法
- 搞股票的投资者和经理都有说英语的行为,定义SpeakEnglish接口,把说英语的方法抽象到这个接口,让股票的投资者和经理实现里面的说英语方法
- 测试类创建4种角色的对象并调用各自的方法
学过UML的同志们可以看下这张类图(灰色线加三角表示实现关系)
实现代码
//Human.java
public class Human {
String name;
int age;
public Human() {}
public Human(String name, int age) {
this.name = name;
this.age = age;
}
}
//Teach.java
public interface Teach {
void teach();
}
//Learn.java
public interface Learn {
void learn();
}
//SpeakEnglish.java
public interface SpeakEnglish {
void speak();
}
//FundManager.java
public class FundManager extends Human implements Teach {
public FundManager() {}
public FundManager(String name, int age) {
super(name, age);
}
@Override
public void teach() {
System.out.println("我是基金经理" + name + ", 正在教炒基");
}
}
//FundInvester.java
public class FundInvester extends Human implements Learn {
public FundInvester() {}
public FundInvester(String name, int age) {
super(name, age);
}
@Override
public void learn() {
System.out.println("我是基金投资者" + name + ", 正在学炒基");
}
}
//SharesInvester.java
public class SharesInvester extends Human implements Learn, SpeakEnglish {
public SharesInvester() {}
public SharesInvester(String name, int age) {
super(name, age);
}
@Override
public void learn() {
System.out.println("我是股票投资者" + name + ", 正在学炒股");
}
@Override
public void speak() {
System.out.println("I could speak English, and you?");
}
}
//SharesManager.java
public class SharesManager extends Human implements Teach, SpeakEnglish {
public SharesManager() {
}
public SharesManager(String name, int age) {
super(name, age);
}
@Override
public void teach() {
System.out.println("我是股票经理" + name + ", 正在教炒股");
}
@Override
public void speak() {
System.out.println("I can speak English, and you?");
}
}
//HumanTester.java
public class HumanTester {
public static void main(String[] args) {
FundManager rain = new FundManager("Rain", 37);
FundInvester mary = new FundInvester("Mary", 24);
SharesManager alice = new SharesManager("Alice", 34);
SharesInvester reno = new SharesInvester("Reno", 21);
rain.teach();
mary.learn();
alice.teach();
alice.speak();
reno.learn();
reno.speak();
}
}
写在后面
解决同一种问题可能有多个方案,没有谁对谁错,关键在于自己对问题结构的理解,分析问题结构时的侧重点在哪。至于这个问题本Reno也可以用C++模拟实现,感兴趣的可以在评论区留言。