面向对象的三大特征:封装、继承、多态
一. 封装
封装:隐藏对象的属性对外只提供可以访问属性的方法
访问修饰符有:
public:公用 任何位置都可以访问
private:私有 ,只允许本类访问
// export导出 可以让其他包可以引用本文件
export class Pet{
//访问修饰符 本类 本包 其他包 子类
//public:公用的 任何位置都可以访问
public id:number
//default 默认
name:string
//private:私有的 只允许本类访问
private sex:string
// 私有的 只允许本类访问
private a(){
console.log('a');
}
constructor(id:number,name:string,sex:string){
this.id=id
this.name=name
this.sex=sex
}
}
1.1如何使用封装
第一步:私有化属性并初始化
第二步提供一个公用的方法来访问属性一般用get/set 或getter/setter来访问属性和设置或赋值
第三步实例化并打印
class Pets{
constructor(id:number, name:string, sex:string,helth:number , love:number ){
this.id=id
this.name=name
this.sex=sex
this.helth=helth
this.love=love
}
// 1.私有化属性
private id:number
private name:string
private sex:string
private helth:number //健康值
private love:number //亲密度
// 2.提供一个公有的方法来访问属性 get/set || getter//setter
public getetId():number{
return this.id
}
public getName():string{
return this.name
}
public getSex():string{
return this.sex
}
public getHelth():number{
return this.helth
}
public getLove():number{
return this.love
}
//set 设置/赋值
public setId(id:number){
this.id=id
}
public setName(name:string){
this.name=name
}
public setSex(sex:string){
this.sex=sex
}
public setHelth(helth:number){
this.helth=helth
}
public setLove(love:number){
this.love=love
}
}
let p:Pets=new Pets(1,'小黑','公',100,100)
// p.helth=99
p.setHelth(90) //调用函数修改属性的值
//必须使用get函数访问属性
console.log(`序号:${p.getetId()},昵称:${p.getName()}`);
二. 继承
继承关键字:extends 子类继承父类的属性和方法
通过export 导出,用import导入
//导包
import { Pet } from "../bb/extends";
//创建父类
class A{
//创建了三个不同修饰符在不同的状态下,子类是否能继承父类的属性
public a1:number
a2:number
private a3:number
//初始化对象
constructor(a1:number,a2:number,a3:number){
this.a1=a1
this.a2=a2
this.a3=a3
}
//获取私有属性 返回a3的值
public getA3():number{
return this.a3
}
//设置获取的私有属性并赋值
public setA3(a3:number){
this.a3=a3
}
//设置 aa方法为私有属性
private aa(){
console.log('私有方法');
}
// 设置bb方法为公有方法
public bb(){
console.log('父类的公有方法');
}
}
//创建子类B 继承了父类 A的属性和方法
class B extends A{
// 子类可以有自己的属性和方法
b1:number
b2:number
b3(){
console.log('b的函数');
console.log(this.a1);
console.log(this.a2);
// 子类无法继承父类的私有属性和方法
// console.log(this.a3);
// this.aa()
this.bb()
}
// 派生类的构造函数必须包含 "super" 调用
constructor( a1:number,a2:number,a3:number,b1:number,b2:number){
// 调用父类的构造函数 必须写在构造函数的第一行
super(a1,a2,a3)
this.b1=b1
this.b2=b2
}
}
let ba:B=new B(1,2,3,4,5)
console.log(ba);
ba.bb()
打印结果:
2.1 关于继承的总结
1.继承的关键字:extends
1.继承的关键字 extends
//列子
class A{
name:string
constructor(name:string){
this.name=name
}
}
class B extends A{}
2.子类继承父类 只能继承一个类(单继承)
3. 一个父类可以有多个子类
class R{
public Name:string
public Sex:string
public chi(){
console.log('吃喝拉撒');
}
constructor(Name:string,Sex:string){
this.Name=Name
this.Sex=Sex
}
}
let h:R=new R('王五','男')
console.log(`姓名:${h.Name},性别:${h.Sex}`);
h.chi()
class H extends R{
fs:string
hs(){
console.log(this.Name+':'+'做好事');
}
constructor(Name:string,Sex:string,fs:string){
super(Name,Sex)
this.fs=fs
}
}
let h1:H=new H('张三','男','白色')
console.log(`姓名:${h1.Name},性别:${h1.Sex},肤色:${h1.fs}`);
h1.hs()
class Huai extends R{
dq:string
hs(){
console.log(this.Name+':'+'做坏事');
}
constructor(Name:string,Sex:string,dq:string){
super(Name,Sex)
this.dq=dq
}
}
let h2:Huai=new Huai('李四','男','日本')
console.log(`姓名:${h2.Name},性别:${h2.Sex},地区:${h2.dq}`);
h2.hs()
4.object类时所有类的父类,没有显示的继承的类都默认继承object
继承了object中转换字符串的toString方法
5.子类必须调用父类的构造函数,构造函数必须在第一行
super:调用父类的构造函数方法
6.子类不能继承父类的私有属性和方法
父类的私有属性无法继承
父类的私有方法
7.在子类中调用父类的属性和方法需要使用this关键字
class Person{
constructor(name:string,sex:string){
this.name=name
this.sex=sex
}
name:string
sex:string
eat(){
console.log('人的吃喝拉撒');
}
}
class GoodPerson extends Person{
color:string
sex:string
constructor(name:string,sex:string,color:string){
super(name,sex)
this.color=color
this.sex=sex
}
hs(){
//调用父类的属性和方法需要使用this关键字
console.log(this.sex+'好人在做好事');
}
8.子类属性和父类属性同名,默认使用子类的属性
上面代码父类有个sex属性,子类也声明了sex属性,我们实例化对象并打印出来看一下效果
//实例化对象
let hr:GoodPerson=new GoodPerson('张三','男','黄')
//调用hs方法
hr.hs()
运行结果:通过运行结果得知:子类属性和父类属性同名,默认使用子类的属性
9.方法可以同名,默认调用子类方法,可以使用super调用父类方法
我们在上面的代码在添加一个eat方法,调用一下父类的eat方法
eat(){
// 调用父类的方法需要使用super关键字
super.eat()
console.log('好人的吃喝拉撒');
}
运行结果:通过运行结果得知:使用super可以调用父类方法,但是只能写到构造函数里
三. 多态
多态有方法的重载,方法的重写等
3.1 方法的重载的概念
在同一个类中,方法名相同,返回值和参数不同,ts中无法使用,arkts中使用
3.2方法的重写
子类重写父类的方法,方法名相同,参数相同,返回值相同或者是其子类
//创建一个父类 A
class A{
a1():void{
console.log('第一个');
}
}
子类 B 继承 父类 A
class B extends A{
a1(): void {
console.log('子类的重写');
}
}
let b:B=new B()
b.a1()
运行结果:打印的子类中a1函数中的打印语句
3.3多态的实例
主人领养宠物,有猫,狗,企鹅
食物:猫吃猫粮 狗吃骨头 企鹅吃鱼
健康度,亲密度:
狗玩接飞盘游戏,亲密度+5,健康值-10 狗吃食物的时候,健康值+3
企鹅玩游戏,亲密度+3,健康值-8 企鹅吃食物的时候,健康值+5
猫玩毛线游戏,亲密度+5,健康值-5 猫吃食物的时候,健康值+5
游戏: 猫玩毛线 狗玩接飞盘 企鹅游泳
(1).创建宠物为父类,狗,企鹅,猫继承宠物类
// 宠物
class Pet{
name:string
sex:string
health:number
love:number
constructor(name:string,sex:string,health:number,love:number){
this.name=name
this.sex=sex
this.health=health
this.love=love
}
eat(food:string){
console.log('宠物在吃'+food+',健康值加1');
this.health+=1 //健康值加1
}
show():string{
return `昵称:${this.name},性别:${this.sex},健康值:${this.health},亲密度:${this.love}`
}
}
// 狗
class Dog extends Pet{
type:string
constructor(name:string,sex:string,health:number,love:number,type:string){
super(name,sex,health,love)
this.type=type
}
// 重写
eat(food:string):void{
if(this.health<=97){
this.health+=3
}else{
this.health=100
}
console.log(`狗在吃:${food},健康值+3,当前健康值:${this.health}`);
}
show():string{
let str:String=super.show()
return str+`,品种:${this.type}`
}
jfp(){
console.log(`狗在接飞盘,健康值-10,亲密度+5`);
this.health-=10
this.love+=5
}
}
// 企鹅
class Pengun extends Pet{
age:number
constructor(name:string,sex:string,health:number,love:number,age:number){
super(name,sex,health,love)
this.age=age
}
eat(food:string):void{
if(this.health<=95){
this.health+=5
}else{
this.health=100
}
console.log(`企鹅在吃:${food},健康值+5,当前健康值:${this.health}`);
}
show():string{
let str:String=super.show()
return str+`,年龄:${this.age}`
}
yy(){
console.log(`企鹅在游泳,健康值-8,亲密度+3`);
this.health-=8
this.love+=3
}
}
// 猫
class Cat extends Pet{
color:string
constructor(name:string,sex:string,health:number,love:number,color:string){
super(name,sex,health,love)
this.color=color
}
eat(food:string):void{
if(this.health<=95){
this.health+=5
}else{
this.health=100
}
console.log(`猫在吃:${food},健康值+5,当前健康值:${this.health}`);
}
show():string{
let str:String=super.show()
return str+`,颜色:${this.color}`
}
mx(){
console.log(`猫在玩毛线,健康值-5,亲密度+5`);
this.health-=8
this.love+=3
}
}
(2). 创建主人类 领养宠物 喂宠物
instanceof:判断一个对象是不是某个类型
class Master{
getPet(p:Pet){
console.log( p.show());
}
//以父类作为形参实现多态
// 喂宠物
feedPet(p:Pet){
// 判断p是不是狗 instanceof:判断一个对象是不是某个类型
if(p instanceof Dog){
p.eat('骨头')
}else if(p instanceof Pengun){
p.eat('鱼')
}else if(p instanceof Cat){
p.eat('猫粮')
}
}
// 玩游戏
play(p:Pet){
// as 断言
// let pg:Pengun=p as Pengun
// pg.yy()
// 判断p是不是狗 instanceof:判断一个对象是不是某个类型
if(p instanceof Dog){
// 前边已经做了类型判断,所以系统会自动把对象转换为对应的类型
p.jfp()
}else if(p instanceof Pengun){
p.yy()
}else if(p instanceof Cat){
p.mx()
}
}
}
let m:Master=new Master()
let dd:Dog=new Dog('小黄','雄',30,40,'泰迪')
let str=m.getPet(dd)
m.feedPet(dd)
let pg:Pengun=new Pengun('小白','雄',30,40,2)
m.getPet(pg)
m.feedPet(pg)
m.play(pg)
let cat1:Cat=new Cat('小花','雌',70,90,'白色')
m.getPet(cat1)
m.feedPet(cat1)
m.play(cat1)
运行结果:
四. 利用DevEcostudio编写一个虚拟宠物程序实例
4.1页面预览
4.2在ets文件夹中创建model文件夹,把上面写的ts文件放入里面
dog.ts文件代码
// 狗
import { Pet } from './Pet'
import { promptAction } from '@kit.ArkUI'
export class Dog extends Pet{
type:string
constructor(name:string,sex:string,health:number,love:number,type:string){
super(name,sex,health,love)
this.type=type
}
// 重写
eat(food:string):void{
if(this.health<=97){
this.health+=3
}else{
this.health=100
}
console.log(`狗在吃:${food},健康值+3,当前健康值:${this.health}`);
}
jfp(){
console.log(`狗在接飞盘,健康值-10,亲密度+5`);
this.health-=10
if(this.health<=0){
this.love=0
promptAction.showToast({message:'健康值太低,已死亡'})
}else if(this.health<=40){
this.love-=10
promptAction.showToast({message:'宠物健康值太低,小心死亡'})
}
if(this.love<=95){
this.love+=5
}else{
this.love=100
}
}
}
Masrer.ts文件代码
// 主人: 领养宠物 喂宠物
import { Cat } from './Cat';
import { Dog } from './dog';
import { Pengun } from './penguin';
import { Pet } from './Pet';
export class Master{
getPet(p:Pet){
}
//以父类作为形参实现多态
// 喂宠物
feedPet(p:Pet){
// 判断p是不是狗 instanceof:判断一个对象是不是某个类型
if(p instanceof Dog){
p.eat('骨头')
}else if(p instanceof Pengun){
p.eat('鱼')
}else if(p instanceof Cat){
p.eat('猫粮')
}
}
// 玩游戏
play(p:Pet){
// as 断言
// let pg:Pengun=p as Pengun
// pg.yy()
// 判断p是不是狗 instanceof:判断一个对象是不是某个类型
if(p instanceof Dog){
// 前边已经做了类型判断,所以系统会自动把对象转换为对应的类型
p.jfp()
}else if(p instanceof Pengun){
p.yy()
}else if(p instanceof Cat){
p.mx()
}
}
}
penguin.ts文件代码
// 企鹅
import { Pet } from './Pet'
import { promptAction } from '@kit.ArkUI'
export class Pengun extends Pet{
age:number
constructor(name:string,sex:string,health:number,love:number,age:number){
super(name,sex,health,love)
this.age=age
}
eat(food:string):void{
if(this.health<=95){
this.health+=5
}else{
this.health=100
}
console.log(`企鹅在吃:${food},健康值+5,当前健康值:${this.health}`);
}
yy(){
console.log(`企鹅在游泳,健康值-8,亲密度+3`);
this.health-=8
if(this.health<=0){
this.love=0
promptAction.showToast({message:'健康值太低,已死亡'})
}else if(this.health<=40){
this.love-=8
promptAction.showToast({message:'宠物健康值太低,小心死亡'})
}
if(this.love<=97){
this.love+=3
}else{
this.love=100
}
}
}
Pet.ts文件代码
// 宠物
export class Pet{
name:string
sex:string
health:number
love:number
constructor(name:string,sex:string,health:number,love:number){
this.name=name
this.sex=sex
this.health=health
this.love=love
}
eat(food:string){
console.log('宠物在吃'+food+',健康值加1');
this.health+=1 //健康值加1
}
}
Cat.ts文件代码
// 猫
import { Pet } from './Pet'
import { promptAction } from '@kit.ArkUI'
export class Cat extends Pet{
color:string
constructor(name:string,sex:string,health:number,love:number,color:string){
super(name,sex,health,love)
this.color=color
}
eat(food:string):void{
if(this.health<=95){
this.health+=5
}else{
this.health=100
}
console.log(`猫在吃:${food},健康值+5,当前健康值:${this.health}`);
}
mx(){
console.log(`猫在玩毛线,健康值-5,亲密度+5`);
this.health-=8
if(this.health<=0){
this.love=0
promptAction.showToast({message:'健康值太低,已死亡'})
}else if(this.health<=40){
this.love-=10
promptAction.showToast({message:'宠物健康值太低,小心死亡'})
}
if(this.love<=97){
this.love+=3
}else{
this.love=100
}
}
}
4.3在主页面创建实例化对象
ResourceStr 资源字符串
@State message: string = '虚拟宠物';
@State ck:number=-1; //-1.未选择 0.企鹅 1.狗 2.猫
//ResourceStr 资源字符串
@State img:ResourceStr=$rawfile('2024-08-28_144259.png')
@State pet:Pet=new Pet('','',80,80)
@State dog:Dog=new Dog('','',0,0,'')
@State pg:Pengun=new Pengun('','',0,0,0)
@State cat:Cat=new Cat('','',0,0,'')
@State flag:boolean=false
创建单选按钮,选中哪个按钮,把里面的值改为相对应的数字,0代表企鹅,1.狗 2.猫 -1未选择
-2:确认页面
如果未领养宠物,则没有输入框,如果选择宠物则出现输入框,输入宠物的姓名等属性
确认按钮:如果没有输入属性值则提示不能为空,健康值和亲密度、年龄不能为非数字
符合要求则领养成功进入喂养页面和玩耍页面 如果健康值小于0宠物则死亡重新进入领养页面
如果亲密度小于0则离家出走
猫:健康值小于40亲密度-10 玩耍健康值-8,亲密度+5,吃食物:健康值+5
狗:健康值小于40亲密度-10 玩耍健康值-10,亲密度+5,吃食物:健康值+3
企鹅:健康值小于40亲密度-8 玩耍健康值-8,亲密度+3,吃食物:健康值+5
Column({space:10}){
Text(this.message)
.fontSize(30)
.fontColor('green')
Row() {
Radio({ value: '狗', group: 'pet' })
.onChange(val => {
this.ck = 1
this.img = $rawfile('dogs.jpg')
this.flag=true
})
.checked(this.flag)
Text('狗').fontSize(20).fontColor('blue')
.margin({ right: 50 })
Radio({ value: '企鹅', group: 'pet' })
.onChange(val => {
this.ck = 0
this.img = $rawfile('pangun.jpg')
})
Text('企鹅').fontSize(20).fontColor('blue')
.margin({ right: 50 })
Row() {
Radio({ value: '猫', group: 'pet' })
.onChange(val => {
this.ck = 2
this.img = $rawfile('cat.jpg')
})
Text('猫').fontSize(20).fontColor('blue')
}
}
.width('90%')
.justifyContent(FlexAlign.Center)
Image(this.img)
.width('300')
.height('300')
.border({width:1,color:'#ccc',style:BorderStyle.Solid})
if(this.ck>=0){
Column({space:10}){
Row(){
TextInput({placeholder:'昵称'}).width('30%').borderRadius(0)
.onChange(val=>{
this.pet.name=val
})
TextInput({placeholder:'性别'}).width('30%').borderRadius(0)
.onChange(val=>{
this.pet.sex=val
})
TextInput({placeholder:'健康值'}).width('30%').borderRadius(0)
.onChange(val=>{
this.pet.health=parseInt(val)
})
}.width('100%').justifyContent(FlexAlign.SpaceAround)
Row(){
TextInput({placeholder:'亲密度'}).width('30%').borderRadius(0)
.onChange(val=>{
this.pet.love=parseInt(val)
})
if(this.ck==0){
TextInput({placeholder:'年龄'}).width('30%').borderRadius(0)
.onChange(val=>{
this.pg.age=parseInt(val)
})
}else if(this.ck==1){
TextInput({placeholder:'品种'}).width('30%').borderRadius(0)
.onChange(val=>{
this.dog.type=val
})
}else if(this.ck==2){
TextInput({placeholder:'颜色'}).width('30%').borderRadius(0)
.onChange(val=>{
this.cat.color=val
})
}
Button('确认').type(ButtonType.Normal).width('30%')
.onClick(()=>{
if(this.ck==0){
let p=this.pg
if(p.name==''&&p.sex==''&&p.health==0&&p.love==0&&p.age==0){
promptAction.showToast({message:'不能为空'})
}else{
if((this.pet.health>=0&&this.pet.health<=100)&&(this.pet.love>=0&&this.pet.love<=100)&&(this.pg.age>=0&&this.pg.age<=100)){
this.pg.name=this.pet.name
this.pg.sex=this.pet.sex
this.pg.health=this.pet.health
this.pg.love=this.pet.love
this.pet=this.pg
this.ck=-2
}else{
promptAction.showToast({message:'健康值和亲密度和年龄不能为非数字'})
}
}
}else if(this.ck==1){
let p=this.dog
if(p.name==''&&p.sex==''&&p.health==0&&p.love==0&&p.type==''){
promptAction.showToast({message:'不能为空'})
}else{
if((this.pet.health>=0&&this.pet.health<=100)&&(this.pet.love>=0&&this.pet.love<=100)){
this.dog.name=this.pet.name
this.dog.sex=this.pet.sex
this.dog.health=this.pet.health
this.dog.love=this.pet.love
this.pet=this.dog
this.ck=-2
}else{
promptAction.showToast({message:'健康值和亲密度不能为非数字'})
}
}
}else if(this.ck==2){
let p=this.cat
if(p.name==''&&p.sex==''&&p.health==0&&p.love==0&&p.color==''){
promptAction.showToast({message:'不能为空'})
}else{
if((this.pet.health>=0&&this.pet.health<=100)&&(this.pet.love>=0&&this.pet.love<=100)){
this.cat.name=this.pet.name
this.cat.sex=this.pet.sex
this.cat.health=this.pet.health
this.cat.love=this.pet.love
this.pet=this.cat
this.ck=-2
}else{
promptAction.showToast({message:'健康值和亲密度不能为非数字'})
}
}
}
})
}.width('100%').justifyContent(FlexAlign.SpaceAround)
}.width('90%')
}else if(this.ck==-2){ //已输入
Column(){
Row(){
Text(`昵称${this.pet.name}`).fontSize(20)
Text(`性别${this.pet.sex}`).fontSize(20)
if(this.pet instanceof Dog){
Text(`品种${this.pet.type}`).fontSize(20)
}else if(this.pet instanceof Pengun){
Text(`年龄${this.pet.age}`).fontSize(20)
}
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
Row(){
Text(`健康值${this.pet.health}`).fontSize(20)
Text(`亲密度${this.pet.love}`).fontSize(20)
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
}.width('90%')
Row(){
Button('喂食').width('30%')
.onClick(()=>{
if(this.pet instanceof Dog){
this.img=$rawfile('dogeatfood.gif')
this.pet.eat('骨头')
}else if(this.pet instanceof Pengun){
this.img=$rawfile('panguineatfood.gif')
this.pet.eat('鱼')
}else if(this.pet instanceof Cat){
this.img=$rawfile('cateatfood.gif')
this.pet.eat('猫粮')
}
})
Button('玩耍').width('30%')
.onClick(()=>{
if(this.pet instanceof Dog){
this.img=$rawfile('fp.gif')
this.pet.jfp()
if(this.pet.health<=0) {
this.flag=false
this.ck = -1
this.img=$rawfile('2024-08-28_144259.png')
}else if(this.pet.love<=0){
this.flag=false
this.ck = -1
this.img=$rawfile('2024-08-28_144259.png')
promptAction.showToast({message:'亲密度太低,宠物离家出走了'})
}
}else if(this.pet instanceof Pengun){
this.img=$rawfile('yy.gif')
this.pet.yy()
if(this.pet.health<=0) {
this.flag=false
this.ck = -1
this.img=$rawfile('2024-08-28_144259.png')
}else if(this.pet.love<=0){
this.flag=false
this.ck = -1
this.img=$rawfile('2024-08-28_144259.png')
promptAction.showToast({message:'亲密度太低,宠物离家出走了'})
}
}else if(this.pet instanceof Cat){
this.img=$rawfile('mx.gif')
this.pet.mx()
if(this.pet.health<=0){
this.flag=false
this.ck=-1
this.img=$rawfile('2024-08-28_144259.png')
}else if(this.pet.love<=0){
this.flag=false
this.ck = -1
this.img=$rawfile('2024-08-28_144259.png')
promptAction.showToast({message:'亲密度太低,宠物离家出走了'})
}
}
})
}.width('90%').justifyContent(FlexAlign.SpaceAround)
}
}
.height('100%')
.width('100%')
}