Java面向对象通俗易懂详解[抽象和封装与多态]

707 阅读7分钟

抽象 封装

1.抽象封装解释

抽象,是指从众多的事务中抽取出具有共同的、本质性的特征作为一个整体。是共同特质的集合形式。抽象是一种编程思想。

封装,是将通过抽象所得到的数据信息和操作进行结合,使其形成一个有机的整体。 内执行操作,对外隐藏细节和数据信息。封装是执行抽象思想的一种手段。封装是将具有共 同特征的属性、行为抽象成为具体的事物,通过添加修饰符来控制外来访问。

如同快递封装商品在包裹中,只在包裹外贴上标签,打印买家姓名、联系电话、商品名称等,其它信息都被封装在里面不让任何人看到。

1627871545(1).jpg

2.再次改进,形成——实体类、接口、抽象行为类、人类行为

下面我们将以上代码进行一些改造。如图所示:

image.png

  • 由 PersonInterface 提供接口方法
  • 由 PersonEntity 提供管理属性类
  • 由 AbstractPersonAction 实现公共的方法,不能实现的往下放
  • 子类如:GrandFatherAction、FatherAction、Child 只关注自己内部具体的行为;
  • 子类可以都直接继承 PersonAction,也可以继承 PersonAction 子类的子类,如:Father 直接继承 PersonAction,而 Child 继承 GrandFather;
  • 调用时候,可以声明为抽象类,PersonAction 类型,如果切换具体的实现类只把 new 之后改动即可。从而达到了提高代码的复用率,修改和重构时改动小; 总之,大原则是:抽象出共同的性质。

3.再次改进后—实体类(源码)

实体类(源代码:com.chapter02.testAbs.PersonEntity):

package com.chapter02.testAbs;

/**
 * 人
 */
public class PersonEntity{
    //身份号码
    private String idCard = "";
    //姓名
    private String name = "";
    //眼睛
    private String eye = "";
    //脸蛋
    private String face = "";
    //鼻子
    private String nose = "";

    /**
     * 无参构造
     */
    public PersonEntity(){
    }

    /**
    * 全参构造
    * @param idCard
    * @param name
    * @param eye
    * @param face
    * @param nose
    */

    public PersonEntity(String idCard, String name,String eye, String face, String nose) {
        this.idCard = idCard;
        this.name = name;
        this.eye = eye;
        this.face = face;
        this.nose = nose;
    }
    //GET 、SET、toString
}

4.再次改进后—接口(源码)

接口(源代码:com.chapter02.testAbs.PersonInterface):

package com.chapter02.testAbs;
/**
 * 人的 接口 ,只关注行为
 */
public interface PersonInterface {
    //创建一个人
    void setPersonEntity(PersonEntity personEntity);
    //得到 一个人
    PersonEntity getPersonEntity();
    //运动天赋行为——跑步
    void run();
    //个性气质行为——脾气
    void batTamper();
    //其他 。。。
}

5.再次改进后—“人”行为抽象类(实现接口源码)

抽象行为类(源代码:com.chapter02.testAbs.AbstractPersonAction):

package com.chapter02.testAbs;
/**
 * 人的 行为抽象
 */
public abstract class AbstractPersonAction implements PersonInterface {
    
    private PersonEntity personEntity;
    //可以 把一 些基 本的 行为写好
    
    @Override
    public void run() {
        p("MyListImpl->run:百米跑步:");
        //跑步行为:
        p ("1.第一步:俯下身子,两手撑地,不能越过开始线。");
        p ("2.第二步:一只腿放在蹬腿机上,准备听从枪声。");
        p ("3.第三步:枪声一向,蹬腿就跑!");
        p (".....冲刺过程,结果如何?不知道,留给子类实现。");
    }

    //输出
    public void p(Object msg) {
        System.out.println (msg);
    }
    
    //如果还不太清楚具体行为,也可 以再 留空 白
    @Override
    public abstract void batTamper();

    @Override
    public PersonEntity getPersonEntity() {
        return personEntity;
    }

    //创建人 的行为,交给这个抽象类完成
    @Override
    public void setPersonEntity(PersonEntity personEntity) {
        this.personEntity = personEntity;
    }
}

6.再次改进后—爷爷行为类(继承抽象类,重写方法源码)

爷爷行为类(源代码:com.chapter02.testAbs.GrandFatherAction):

package com.chapter02.testAbs;

/**
 * 爷爷
 */
public class GrandFatherAction extends AbstractPersonAction {

    /**
     * 跑步
     */
    @Override
    public void run() {
        super.run ();
        //继续行为
        super.p("4.第四步:我跑啊,眼睛往两侧扫描,发现有人快超我了");
        super.p("5.第五步:我咬紧牙关拼命跑,终于第一个跑到终点。");
        super.p("6.第六步:最终成绩:11.8 秒/100 米!破纪录了!NO.1! ");
    }

    /**
     * 脾气
     */
    @Override
    public void batTamper() {
        System.out.println ("脾气很好。");
    }
}

7.再次改进后—爸爸行为类(继承抽象类源码)

爸爸行为类(源代码:com.chapter02.testAbs.FatherAction):

package com.chapter02.testAbs;

/**
 * 爸爸,老爸比较悲催 ,没有继承爷爷的强 大基 因,只继承了 普通屌丝人类行为
 */
public class FatherAction extends AbstractPersonAction {
    @Override
    public void run() {
        super.p ("我压根就不会跑步,也没有继承老爸的强大基因!");
    }

    @Override
    public void batTamper() {
        super.p ("我的脾气不太好,暴躁 !");
    }
}

8.再次改进后—还在行为类(继承爷爷类源码)

孩子行为类(源代码:com.chapter02.testAbs.ChildAction):

package com.chapter02.testAbs;

/**
 * 孩子 ,直接继承爷爷的,隔 代遗传啊
 */
public class ChildAction extends GrandFatherAction {

}

9.再次改进后—调用:创建接口对象(面向接口编程源码)

调用测试(源代码:com.chapter02.testAbs.CallMain):

package com.chapter02.testAbs;

/**
 * 调用方 法
 */

public class CallMain {

    //测试
    public static void main(String[] args) {
        //用 PersonInterface 接口 定义对象类型。
        PersonInterface person = new
        ChildAction ();
        //把创建人 的工 作交给抽象类完成
        person.setPersonEntity (new Boy("500234519981205112988","刘军军","眼睛度数 5.8","方正脸","鹰钩鼻"));

        //基本 信息
        System.out.println (person.getPersonEntity ().getName ()+"的基本信息==>>"+person.getPersonEntity ().toString ());

        //跑的行为
        person.run ();
        System.out.println ("----------我只是一个分隔符---------");

        //创建一个爸爸对象。注 意:下方调用一个都不 用改动!
        person = new FatherAction ();
        //把创建人 的工 作交给抽象类完成
        person.setPersonEntity (new PersonEntity ("50023451969120511666","刘大能","高度近视","国字脸","大鼻子"));

        //基本 信息
        System.out.println(person.getPersonEntity ().getName()+"的基本信息==>>"+person.getPersonEntity ().toString ());

        //跑的行为
        person.run ();
    }
}

为了更加明确的分工,改造后特点:

1)由 MyListInterface 提供接口方法

2)由 Person 提供管理属性类

3)由 MyListImpl 实现公共的方法,不能实现的往下放

4)子类如:GrandFatherAction、FatherAction、Child 只关注自己内部具体的行为

5)子类可以都直接继承 PersonAction,也可以继承 PersonAction 子类的子类,如:Father 直接继承 PersonAction,而 Child 继承 GrandFather。

6)调用时候,可以声明为抽象类,PersonAction 类型,如果切换具体的实现类只把new 之后改动即可。从而达到了提高代码的复用率,修改和重构时改动小。

总之,大原则是:分离出属性、行为

运行结果:

刘军军的基本信息==>>人:{idCard='500234519981205112988', name='刘军军',eye='眼睛度数 5.8', face='方正脸', nose='鹰钩鼻'}
AbstractPersonAction->run:百米跑步:
1.第一步:俯下身子,两手撑地,不能越过开始线。
2.第二步:一只腿放在蹬腿机上,准备听从枪声。
3.第三步:枪声一向,蹬腿就跑!
.....冲刺过程,结果如何?不知道,留给子类实现。
4.第四步:我跑啊,跑啊,跑啊,眼睛往两侧扫描,发现有人快超我了。
5.第五步:我咬紧牙关拼命跑,终于第一个跑到终点。
6.第六步:最终我的成绩是:11.8 秒/100 米!破纪录了!NO.1,�
---------------我只是一个分隔符----------------
刘大能的基本信息==>>人:{idCard='50023451969120511666', name='刘大能', eye='高度近视', face='国字脸', nose='大鼻子'}
我压根就不会跑步,也没有继承老爸的强大基因!
Process finished with exit code 0

通过以上的改进,程序大大有改观,首先抽象的行为类可以写公共的行为方法。子类可以拥有抽象行为方法的同时,还可以自己创建新的行为。未来,“人”的行为越来越多,就可以扩展出更多的行为子类。

多态

教科书解释是:继承、重写、父类引用指向子类对象。

以上的孩子、爸爸、爷爷三个类,存在继承关系。

1.子类重写父类方法

如以上的子类中对 run 方法重写,覆盖了父类的方法,如下代码:

@Override
public void run() {
    System.out.println ("我压根就不会跑步,也没有继承老爸的强大基因!");
}

以上是多态的重写特征。

2.父类引用指向子类对象

接着,我们将以上的人的实体类改进一下,再增加男孩、女孩两个类来继承 PerosnEntity实体类。如下结构变为:

image.png

其实这已经非常接近工厂方法模式(下面有介绍)

其中在抽象行为类中是这样传递参数:

//创建人的行为,交给这个抽象类完成
@Override
public void setPersonEntity(PersonEntity personEntity) {
    this.personEntity = personEntity;
}

调用时,我们是这样子传参数(不是传 PerosnEntity 而是 Boy):

//把创建人的工作交给抽象类完成
person.setPersonEntity (new Boy(
    "500234519981205112988",
    "刘军军",
    "眼睛度数 5.8",
    "方正脸",
    "鹰钩鼻")
);

像以上这样通过子类对象作为参数改变内部行为,也是一种多态的体现。

以上在整个“第 9 节 抽象和封装”示例源码的基础上增加了两个类:

com.chapter02.testAbs.Boy、com.chapter02.testAbs.Boy.Girl。