C#学习(面向对象)Day09——抽象类和抽象方法,密封类和密封方法,静态,单例模式
1.抽象类和抽象方法:
using System;
namespace Day14_1
{
//理论知识
//抽象类和抽象方法
//abstruct class 抽象方法
//abstruct 抽象方法
//不能有方法体,大括号都不能有
//抽象方法一定要重写,不重写就报错
//抽象方法在普通子类中必须重写,在抽象子类中可以重写也可以不重写
//抽象类允许声明对象,但是抽象类不能进行实例化对象,但可以有构造方法,构造方法不能是抽象方法
//因为子类新建的时候要调用父类的构造函数,所以即使父类是抽象类也得有构造函数
//抽象方法一定在抽象类里,抽象类里不一定有抽象方法。
//一般抽象类里有抽象方法,可以有普通方法存在。
//普通类要把抽象父类的所有抽象方法全部重写
abstract class Sportsman //**********************抽象类
{
//抽象类的特性
//抽象类不能使用new关键字进行实例化,抽象类是不完整的
//抽象类除了可以拥有普通类成员外还可以有抽象方法
//从抽象类派生的非抽象类必须实现抽象类当中的所有抽象方法
//抽象类不能被实例化但可以有构造方法,构造方法不能为抽象方法
//不能使用sealed修饰符修饰抽象类,因为采用sealed修饰符的类是无法被继承的,而抽象类是必须被继承的
public abstract void Train(); //*********************抽象方法
//抽象方法的特性
//抽象方法是隐式的虚方法
//抽象方法只能有声明不提供实际的实现
//抽象方法必须被子类重写并实现,或使其子类依旧为抽象类
//抽象方法的访问修饰符不能是private,不然就无法被子类访问了,也就无法重写了
//抽象⽅法的关键词abstruct
//abstruct 返回值类型(参数列表)
//抽象⽅法必须要放在抽象类⾥⾯
//抽象⽅法没有⽅法体: [访问修饰符] abstruct 返回值类型 ⽅法名(形参列表);
//抽象⽅法的访问修饰符不能是private
//抽象类即可以放抽象⽅法,也可以放普通⽅法
//抽象⽅法必须在⼦类中全部实现
//除⾮⼦类也是⼀个抽象类,那么可以先不实现该抽象⽅法
//抽象⽅法和虚⽅法最⼤的区别
//抽象⽅法必须其派⽣类中得以实现
//⽽虚⽅法不是⼀定要在其派⽣类去重写
//⽆论是虚⽅法还是抽象⽅法,⼦类进⾏了重写【实现】
//那么⼦类的⼦类依旧可以继续重写
//抽象类不能⽤sealed关键词修饰
//总结:override可以重写哪些⽅法呢?
//带有virtual、abstruct、override关键词的⽅法
public void Eat()
{
Console.WriteLine("吃饭");
}
}
class FootballSportsman : Sportsman
{
//问题2.训练方法可以重写,也可以不重写
//public override void Train()
//{
// Console.WriteLine("跑步、射门、传球");
//}
public override void Train() //************************抽象方法的重写,关键字override
{
Console.WriteLine("跑步、射门、传球");
}
}
abstract class SwimSportsman : Sportsman
{
/*
*
*/
public override void Train()
{
Console.WriteLine("游泳");
}
}
class FreedomSwimSportsman : SwimSportsman
{
public override void Train()
{
Console.WriteLine("摆臂、蹬腿、换气");
}
}
class Breaststroke : SwimSportsman
{
public override void Train()
{
Console.WriteLine("蛙泳");
}
}
class Program
{
//以运动员为背景
static void Main(string[] args)
{
//Sportsman Liuxiang = new Sportsman();
////问题1.方法体为空,不知道训练什么
//Liuxiang.Train();
//Sportsman yaoming;抽象类允许声明对象
Sportsman wulei = new FootballSportsman();
wulei.Train();
Sportsman xiaomming = new Breaststroke();
Sportsman xiaohong = new FreedomSwimSportsman();
xiaohong.Train();
xiaomming.Train();
}
}
}
2.密封类和密封方法:
using System;
namespace Day14_2
{
class Program
{
sealed class Time //******************密封类
{
//sealed关键词修饰的类称之为密封类
//语法:sealed class 类名
//密封类是不能被别的类继承的
public string date;
public string time;
}
//class TestClass : Time
//{
//
//}
abstract class Sportsman
{
public abstract void train();
}
class Runningman : Sportsman
{
public sealed override void train() //************************密封方法
{
//sealed关键词修饰的重写的⽅法,称之为密封⽅法
//语法:sealed override 返回值类型 ⽅法名(参数列表)
//密封⽅法⽆法再次被其⼦类重写
Console.WriteLine("力量练习");
}
public virtual void Match()
{
}
}
class LongTimeRunningman : Runningman
{
}
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
}
3.静态:
using System;
using System.Runtime.CompilerServices;
namespace Day14_3
{
class Person
{
//静态字段
public static long population = 7000000000;
public static int historylength = 5000;
//静态类中的常数
//可以全大写也可以大驼峰
public const float Player_MoveSpeed = 5;
//静态构造函数
//1.前面不允许添加访问修饰符
//2.不能有参数
//3.执行的时间节点:第一次访问静态类里的字段、属性或方法时
static Person()
{
Console.WriteLine("Person 静态构造");
}
//静态属性
public static long Getpopulation
{
get
{
return population;
}
}
//静态方法
public static void test()
{
}
}
class Program
{
//静态
//只跟类有关系,跟对象无关
//静态类、静态字段、静态属性、静态方法
//静态方法里不能出现成员的字段、属性、方法
//成员方法里可以正常访问静态字段、属性、方法
//普通类中可以有静态字段、属性、方法
//静态类的主要用途
//1.用于调用类中的静态字段、属性、方法
//2.存储静态变量
//静态成员随着类的加载而加载,无论对一个类创建多少个实例,静态成员都只有一个副本
//静态成员:静态成员变量是和类相关联的,可以作为类中“共”有的变量(是一个共性的表现),
//静态成员不依赖特定对象的存在,访问的时候通过类来操作的。
//静态成员使用static关键字修饰。
//静态方法可以被重载但不能被重写,因为他们是属于类,不属于任何实例的
//静态成员由类名通过点语法调用,非静态成员是由对象来调用
//静态方法只能访问静态成员,包括静态成员变量和静态方法;实例方法可以访问实例成员变
//量与实例方法,也可以访问静态成员
//常数
//一直保持不变,跟类有关,与对象无关
//关键词 static
//静态成员
//成员:字段、属性、⽅法
//静态:跟对象没有任何关系,只跟类有关系
//静态成员在何时开辟的内存
//第⼀次访问这个类的时候【第⼀次⽤到这个类的时候】
//⽐如:⽤这个类名去实例化⼀个对象
//⽐如:⽤这个类型去访问⼀个静态字段
// 静态成员在何时释放内存
//在程序结束的时候才会释放
// 普通的实例成员,每有⼀个对象,就有⼀个该成员
//⽽静态成员,跟对象没有关系,所以⽆论有多少个对象,静态成员都只有⼀个
// 例: 实例成员【name】,每有⼀个⼈,就会有对应的⼀个名字
//⽽静态成员【Population】,跟对象没有关系,⽆论有多少个实例对象,⼈⼝数量只
// 有⼀个
// 静态⽅法中是不可以访问⾮静态的成员的
// 不能访问⾮静态的字段、属性
// 不能调⽤⾮静态的⽅法
//⾮静态⽅法中是可以访问静态成员的
// 能访问静态的字段、属性
// 能调⽤静态的⽅法
// 静态⽅法是可以有重载
// 静态类
//静态的成员可以放在静态类中,也可以放在⾮静态类中
// 静态类中只能存在静态成员,不能存在⾮静态的成员
// 静态类是不能进⾏实例化的
// 静态构造函数
//只有⼀种写法
//static 类名()
//静态构造函数必须⽆参数
// 静态构造函数在什么时候才会调⽤
//静态构造函数在程序运⾏期间只会执⾏⼀次
// 在第⼀次访问该类的时候调⽤
//⽤这个类去new⼀个对象
//⽤这个类去访问某个静态成员
//⽤这个类去调⽤某个静态⽅法
// 如果有继承关系
//静态构造函数的执⾏顺序是:
//先执⾏⼦类的静态构造,再执⾏⽗类的静态构造
// 静态构造有什么作⽤
//⼀般⽤于对静态成员进⾏初始化
static void Main(string[] args)
{
Console.WriteLine(Person.population);
Console.WriteLine(Person.historylength);
Console.WriteLine(Person.Player_MoveSpeed);
}
}
}
4.单例模式:
using System;
namespace Day14_4
{
//设计模式:
//设计模式是指前人反复设计实践,总结出来的代码架构设计思路或模式。
//在Unity引擎阶段,使用最多的就是单例模式
//单例类
class Singleton
{
private static Singleton instance;
public static Singleton GetInstance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
private Singleton()
{
}
}
//单例类
class AudioManager
{
private static AudioManager instance;
public static AudioManager GetInstance()
{
if (instance == null)
{
instance = new AudioManager();
}
return instance;
}
}
class GameData
{
private GameData()
{
}
//实现单例的方法
//1.用只读属性来实现
//public static GameData Instance
//{
// get { return instance; }
//}
//2.让某个静态字段只能读不能写 readonly
//public static readonly GameData instance = new GameData();
//3.使用静态方法(懒加载),用的时候才加载
private static GameData instance;
public static GameData GetInstance()
{
if (instance == null)
{
instance = new GameData();
}
return instance;
}
public string GameTime;
}
class Program
{
//对于系统中的某些类来说,只有一个实例很重要,例如,一个游戏数据内容,整个游戏只有
//这么一份,在游戏进行到不同部分时,需要记录或访问该游戏数据。针对这种情况如果某个
//类只能有一个实例那么则满足我们的需求,我们将满足某个类只有一个实例的代码设计方式
//称为单例模式。
//单例模式的三要点:
//(1)某个类只能有一个实例
//(2)必须自行创建这个实例
//(3)必须自行向外界提供这个实例
//-------------------------------------------------------------------
//单例模式实现步骤
//默认构造使用private修饰
//内建该类的静态实例
//静态构造方法中给该静态实例做初始化
//对外提供获取该静态实例的方法
//-------------------------------------------------------------------
//单例模式实现
/*
public class SingleTon
{
private SingleTon() { } //构造方法必须私有化
private static SingleTon instance; //定义静态实例
public static SingleTon GetInstance()
{ //对外提供获取该实例的接口
if (instance == null)
{
instance = new SingleTon();
}
return instance;
}
}*/
//-------------------------------------------------------------------
//单例的使用
//SingleTon singleton = SingleTon.GetInstance();
//Console.WriteLine(singleton.name);
static void Main(string[] args)
{
GameData ins = GameData.GetInstance();
Console.WriteLine(ins==GameData.GetInstance());
Console.WriteLine(GameData.GetInstance()==null);
}
}
}
作业:
1.定义抽象类Shape,类中有两个抽象⽅法,分别是求⾯积Area和周⻓Circumference。
定义圆类Circle,继承⾃Shape,类中有成员变量radius表示半径,实现Shape中求周⻓和 ⾯积的⽅法
定义三⻆形类Rectangle,继承⾃Shape,类中有成员变量length,width表示⻓和宽, 实现Shape中的求周⻓和⾯积的⽅法
定义静态⽅法求⼀个图形的⾯积和周⻓,传⼊不同的参数,查看计算结果
using System;
namespace test_1
{
//抽象类Shape
abstract class Shape
{
//抽象方法求面积
public abstract double Area();
//抽象方法求周长
public abstract double Circumference();
}
//圆类
class Circle : Shape
{
//半径
public double radius;
//重写抽象父类方法求面积
public override double Area()
{
return Math.PI * radius * radius;
}
//重写抽象父类方法求周长
public override double Circumference()
{
return 2 * Math.PI * radius;
}
}
//矩形类
class Rectangle : Shape
{
//长度
public int length;
//宽度
public int width;
//重写抽象父类方法求面积
public override double Area()
{
return length * width;
}
//重写抽象父类方法求周长
public override double Circumference()
{
return 2 * (length + width);
}
}
//正方形类
class Square : Shape
{
//边长
public int side;
//重写抽象父类方法求面积
public override double Area()
{
return side * side;
}
//重写抽象父类方法求周长
public override double Circumference()
{
return side * 4;
}
}
class Test
{
public static double GetArea(double radius)
{
return Math.PI * radius * radius;
}
public static double GetArea(double length,double width)
{
return length * width;
}
public static double GetCircumference(double radius)
{
return Math.PI * radius * 2;
}
public static double GetCircumference(double length,double width)
{
return (length + width) * 2;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("------------------------------------------");
Circle test1 = new Circle();
test1.radius = 5;
Console.WriteLine(test1.Area());
Console.WriteLine(test1.Circumference());
Console.WriteLine("------------------------------------------");
Rectangle test2 = new Rectangle();
test2.length = 3;
test2.width = 4;
Console.WriteLine(test2.Area());
Console.WriteLine(test2.Circumference());
Console.WriteLine("------------------------------------------");
Square test3 = new Square();
test3.side = 6;
Console.WriteLine(test3.Area());
Console.WriteLine(test3.Circumference());
Console.WriteLine("------------------------------------------");
Test.GetArea(1);
Test.GetArea(1, 2);
Test.GetCircumference(1);
Test.GetCircumference(1, 2);
}
}
}
2.模拟植物⼤战僵⼫
定义僵⼫类: 公共成员变量:总⾎量
⽅法:受伤掉⾎(抽象⽅法)、死亡(抽象⽅法)
定义普通僵⼫类继承于僵⼫类
定义有防具(路障)僵⼫类继承于僵⼫类:
特有成员变量:是否有防具
特有⽅法:防具被打烂
在Main⽅法⾥⾯⾥⽤循环语句模拟攻击: 两只个僵⼫对象同时被攻击
普通僵⼫被打击时:每次掉⾎3.
路障僵⼫被打击时:有路障时,每次失⾎2,⾎量剩余⼀半时,防具被打拦,之后 每次失⾎3.
循环攻击过程中:每个僵⼫被攻击时,输出本次丢失⾎量,剩余⾎量。失去道具 时,输出丢失的道具,僵⼫死亡时,输出已死亡。 最后⼀个僵⼫死亡时,攻击停⽌,循环结束,输出总攻击次数。
using System;
namespace test_2
{
//僵尸类
abstract class Zombie
{
//血量
public int HP;
//抽象方法,受伤掉血
public abstract void Injured();
//抽象方法,死亡
public abstract void Dead();
}
//普通僵尸类
class GeneralZombie : Zombie
{
public override void Dead()
{
Console.WriteLine("普通僵尸已死亡...");
}
public override void Injured()
{
if (HP<=0)
{
Dead();
}
Console.WriteLine($"普通僵尸正在受到攻击,受伤掉血2点,剩余血量{HP}");
}
}
//路障僵尸类
class BarricadesZombie : Zombie
{
public bool Armor;
public override void Dead()
{
Console.WriteLine("路障僵尸已死亡...");
}
public override void Injured()
{
if (HP <= 0)
{
Dead();
}
if (Armor)
{
HP -= 2;
Console.WriteLine($"路障僵尸正在受到攻击,受伤掉血2点,剩余血量{HP}");
return;
}
HP -= 3;
Console.WriteLine($"路障僵尸正在受到攻击,受伤掉血3点,剩余血量{HP}");
}
public void ArmorIsBreaked()
{
Armor = false;
Console.WriteLine("路障僵尸装备已打烂...");
}
}
class Program
{
static void Main(string[] args)
{
GeneralZombie test1 = new GeneralZombie();
test1.HP = 10;
BarricadesZombie test2 = new BarricadesZombie();
test2.HP = 20;
test2.Armor = true;
int flag = 0;
for (int i = 0; ; i++)
{
if (test1.HP<=0 &&test2.HP<=0)
{
break;
}
flag++;
//普通僵尸
if (test1.HP > 0)
{
test1.HP -= 3;
test1.Injured();
}
//路障僵尸
if (test2.HP > 10)
{
test2.Injured();
}
else if (test2.HP <= 10)
{
test2.ArmorIsBreaked();
test2.Injured();
}
Console.WriteLine("------------------------------------------");
}
Console.WriteLine(flag);
}
}
}
3.模拟装备商店
定义静态类GoodStore表示物品商店。
物品商店中有销售消耗品Comsumabel,装备类 Equipment,武器Weapon,这三种物品都继承于抽象类物品类Goods。
静态类GoodStore中有三个货柜(数组)分别出售消耗品,装备,武器。在静态构造函 数当中初始化这三个货柜,定义⽅法,当主⻆想买某种类型的物品,商店能够全部打印 出来进⾏介绍。
抽象类Good: 字段:name(string),type(包括消耗品,装备,武器,可以使⽤枚举来表示), buyPrice(买⼊价格,int),salePrice(卖出价格,int) 抽象⽅法:Description(⽤于每类物品的详细说明)
消耗品: 特有字段:hpAdd(int),mpAdd(int)
装备类: 特有字段:propertyAdd(int)
武器类: 特有字段:attack(攻击⼒,int)
using System;
namespace test_3
{
enum Type
{
消耗品,
装备,
武器,
}
//静态商店类
static class GoodStore
{
public static Comsumabel[] comsumabels;
public static Equipment[] equipments;
public static Weapon[] weapons;
static GoodStore()
{
comsumabels = new Comsumabel[10];
equipments = new Equipment[10];
weapons = new Weapon[10];
}
}
//抽象商品类
abstract class Goods
{
public string name;
public Type type;
public int buyPrice;
public int salePrice;
protected Goods(string name, Type type, int buyPrice, int salePrice)
{
this.name = name;
this.type = type;
this.buyPrice = buyPrice;
this.salePrice = salePrice;
}
public abstract void Description();
}
//消耗品类
class Comsumabel : Goods
{
public int hpAdd;
public int mpAdd;
public Comsumabel(string name, Type type, int buyPrice, int salePrice, int hpAdd, int mpAdd) : base(name, type,
buyPrice, salePrice)
{
this.hpAdd = hpAdd;
this.mpAdd = mpAdd;
}
public override void Description()
{
Console.WriteLine($"我是{name},类型是{type},买入价格为{buyPrice},卖出价格为{salePrice},加血量{hpAdd},回蓝量{mpAdd}...");
}
}
//装备类
class Equipment : Goods
{
public Equipment(string name, Type type, int buyPrice, int salePrice, int propertyAdd) : base(name, type,
buyPrice, salePrice)
{
this.propertyAdd = propertyAdd;
}
public int propertyAdd;
public override void Description()
{
Console.WriteLine($"我是{name},类型是{type},买入价格为{buyPrice},卖出价格为{salePrice},属性加成{propertyAdd}...");
}
}
//武器类
class Weapon : Goods
{
public Weapon(string name, Type type, int buyPrice, int salePrice, int attack) : base(name, type, buyPrice,
salePrice)
{
this.attack = attack;
}
public int attack;
public override void Description()
{
Console.WriteLine($"我是{name},类型是{type},买入价格为{buyPrice},卖出价格为{salePrice},攻击力为{attack}...");
}
}
class Program
{
static void Main(string[] args)
{
GoodStore.comsumabels[0] = new Comsumabel("血药", (Type) 0, 10, 8, 100, 50);
GoodStore.comsumabels[1] = new Comsumabel("大血药", (Type) 0, 20, 10, 200, 100);
GoodStore.equipments[0]= new Equipment("布甲", (Type) 1, 20, 10, 50);
GoodStore.equipments[1]= new Equipment("护甲", (Type) 1, 40, 20, 100);
GoodStore.weapons[0] = new Weapon("宝剑", (Type) 2, 30, 15, 50);
GoodStore.weapons[1] = new Weapon("血之宝剑", (Type) 2, 60, 25, 100);
Console.WriteLine("请输入您要买的物品类型");
string type = Console.ReadLine();
if (type == "消耗品")
{
for (int i = 0; GoodStore.comsumabels[i] != null; i++)
{
GoodStore.comsumabels[i].Description();
}
}
else if (type == "装备")
{
for (int i = 0; GoodStore.equipments[i] != null; i++)
{
GoodStore.equipments[i].Description();
}
}
else if (type == "武器")
{
for (int i = 0; GoodStore.weapons[i] != null; i++)
{
GoodStore.weapons[i].Description();
}
}
}
}
}
更多推荐
所有评论(0)