每日一问:为啥建议组合优先与继承?
举个例子:程序员David声明A,程序员Tom刚好写程序看到A,觉得A就是自己直接继承就可以用的,于是写了B继承A
public class A {
private String age;
private String name;
public A(String age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "A{" +
"age='" + age + '\'' +
", name='" + name + '\'' +
'}';
}
}
public class B extends A{
private String address;
public void setAddress(String address) {
this.address = address;
}
public B(String age, String name) {
super(age, name);
}
public static void main(String[] args) {
B b = new B("12","张三");
System.out.println(b);
}
}
结果:
A{age='12', name='张三'}
Process finished with exit code 0
过了一段时间,David觉得要再自己声明的A类上加个参数job
public class A {
private String age;
private String name;
private String job;
public A(String age, String name,String job) {
this.age = age;
this.name = name;
this.job = job;
}
@Override
public String toString() {
return "A{" +
"age='" + age + '\'' +
", name='" + name + '\'' +
'}';
}
}
于是Tom写的代码就出现了错误,然而David自始至终都不知道Tom用了自己的代码。
因为子类和父类有太多的不确定性和易变性导致为啥不建议随意继承的原因了。
与方法调用不同的是,继承会破坏封装。
接下来用代码来举例说明怎么运用组合(非effivective java书上例子):
1.声明所有类公用的OrganizationComponent抽象类,实现所有类共有的接口默认行为,用于访问和管理Component子部件。add(),remove()方法叶子节点不需要实现,故不定义成抽象方法,而是采用默认实现;print()方法,子类都需要实现,故定义成抽象方法。
public abstract class OrganizationComponent {
private String name;//名字
private String des;//说明
public OrganizationComponent(String name, String des) {
this.name = name;
this.des = des;
}
//叶子节点不需要实现,故不定义成抽象方法,而是采用默认实现
protected void add(OrganizationComponent organizationComponent){
//默认实现
throw new UnsupportedOperationException();
}
protected void remove(OrganizationComponent organizationComponent){
//默认实现
throw new UnsupportedOperationException();
}
//抽象方法print(),子类都需要实现
protected abstract void print();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
}
2. City类,Composite非叶子节点,通过组合方式管理county,表示城市
public class City extends OrganizationComponent{
//存放County
List<OrganizationComponent> list = new ArrayList<>();
//构造器
public City(String name, String des) {
super(name, des);
}
@Override
protected void add(OrganizationComponent organizationComponent) {
list.add(organizationComponent);
}
@Override
protected void remove(OrganizationComponent organizationComponent) {
list.remove(organizationComponent);
}
@Override
protected void print() {
System.out.println("----------------------"+this.getName()+"-----------------"+this.getDes()+"-------");
//遍历list
for (OrganizationComponent organizationComponent : list) {
organizationComponent.print();
}
}
}
3.County类,Composite非叶子节点,通过组合方式管理Town,表示县
public class County extends OrganizationComponent{
//存放town
List<OrganizationComponent> list = new ArrayList<>();
public County(String name, String des) {
super(name, des);
}
@Override
protected void add(OrganizationComponent organizationComponent) {
//实际中,County中的添加方法与town中逻辑可能不一样
list.add(organizationComponent);
}
@Override
protected void remove(OrganizationComponent organizationComponent) {
list.remove(organizationComponent);
}
@Override
protected void print() {
System.out.println("------------"+this.getName()+"------"+this.getDes()+"-----------");
for (OrganizationComponent organizationComponent : list) {
organizationComponent.print();
}
}
}
4.Town类,Leaf叶子节点,表示村
public class Town extends OrganizationComponent{
public Town(String name, String des) {
super(name, des);
}
@Override
protected void print() {
System.out.println(" "+getName()+" ---"+this.getDes()+"");
}
public static void main(String[] args) {
OrganizationComponent city = new City("合肥市", "安徽省省会");
OrganizationComponent county = new County("上牌镇", "肥西县县城");
OrganizationComponent county2 = new County("南京镇", "散扯聚集地");
county.add(new Town("王小村","碧霞门聚集地"));
county.add(new Town("拐把村","不定弄扛把子聚集地"));
county2.add(new Town("南京村1","都是高手聚集地1"));
county2.add(new Town("南京村2","都是高手聚集地2"));
city.add(county);
city.add(county2);
city.print();
}
}
结果:
----------------------合肥市-----------------安徽省省会-------
------------上牌镇------肥西县县城-----------
王小村 ---碧霞门聚集地
拐把村 ---不定弄扛把子聚集地
------------南京镇------散扯聚集地-----------
南京村1 ---都是高手聚集地1
南京村2 ---都是高手聚集地2
Process finished with exit code 0
之所以没用本书上的案例主要是考虑书上的案例大多数人一看代码就开始头晕,而以上代码逻辑非常清楚而且案例风趣(有惊喜噢~)
总而言之,继承非常强大,但也存在问题,因为它会破坏封装。只有当子类和超类之间存在真正的子类型关系时(这种情况概率比较低),才适合使用继承。即便如此,如果子类与超类之间在不同的包中,并且超类不是为继承而设计的,那么继承有可能导致脆弱性。为了避免这种脆弱性,应该使用组和并转发方式而不是继承,特别是在存在一个合适的接口来实现包装器类的情况下。包装器类不仅比子类更健壮,而且更强大。
所有文章无条件开放,顺手点个赞不为过吧!