抽象 封装
1.抽象封装解释
抽象,是指从众多的事务中抽取出具有共同的、本质性的特征作为一个整体。是共同特质的集合形式。抽象是一种编程思想。
封装,是将通过抽象所得到的数据信息和操作进行结合,使其形成一个有机的整体。 内执行操作,对外隐藏细节和数据信息。封装是执行抽象思想的一种手段。封装是将具有共 同特征的属性、行为抽象成为具体的事物,通过添加修饰符来控制外来访问。
如同快递封装商品在包裹中,只在包裹外贴上标签,打印买家姓名、联系电话、商品名称等,其它信息都被封装在里面不让任何人看到。
2.再次改进,形成——实体类、接口、抽象行为类、人类行为
下面我们将以上代码进行一些改造。如图所示:
- 由 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实体类。如下结构变为:
其实这已经非常接近工厂方法模式(下面有介绍)
其中在抽象行为类中是这样传递参数:
//创建人的行为,交给这个抽象类完成
@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。