实例详解C#抽象类及其用法(转)

今天学习抽象类和方法,对应该什么时候使用大伤脑筋,百度文库中找到一篇《实例详解C#抽象类及其用法》,觉得该例子通俗易懂,很好地解释了为什么要使用、如何使用抽象类和抽象方法,遂复制过来留存。

假如现在要开发一个模拟CS的游戏。要求如下:

1、游戏中要有恐怖分子,一个恐怖分子一次只能持有一支枪

2、游戏中有多种枪支

3、恐怖分子可以选择枪支使用

4、恐怖分子可以开枪杀人仅此4条,为了使程序足够简单,能说明我们主要目标就行,所以我们用控制台程序来模拟实现。

方法1我们先来看第一种实现情况,假设,游戏中现在有*枪(Pistol)和步枪(Rifle),那么我们必然需要有对应的两个枪械的类。

//**类
public class Pistol
{
public void Shoot()
{
Console.WriteLine("**开始射击:叭叭叭");
}
}
//步枪类
 public class Rifle
{
public void Shoot()
{
Console.WriteLine("步枪开始射击:哒哒哒。。");
}
} 

有了枪械,就可以来实现游戏中的恐怖分子了。业务清单中有一条,匪徒可以选择所用枪支,那么,我们的类可能就需要实现为下边的情况。

 //恐怖分子类
public class Terrorist
{
private Pistol pistol;
private Rifle rifle;
public void SetGun(object gun) //换枪
{
if (gun is Pistol)
{
pistol = (Pistol)gun; //只能拿一支枪,在拿*枪的同时,
rifle = null; //要让步枪为null
}
else
{
rifle = (Rifle)gun;
pistol = null;
}
}
public void KillEnemy()
{
Console.WriteLine("恐怖分子开始杀人!");
 if (rifle == null)
{
pistol.Shoot();
}
else
{
rifle.Shoot();
 }
}
} 

如果运行游戏,还需要有个表示层。我们这样来调用这写类:

class Program
 {
static void Main(string[] args)
{
Terrorist laDeng = new Terrorist();//new出来一个拉登
laDeng.SetGun(new Pistol());//给他一支*枪
laDeng.KillEnemy();//拉登开枪
laDeng.SetGun(new Rifle());
laDeng.KillEnemy();
}
}

好了,程序写到这里就基本实现了我们的业务要求,我们来分析下程序的结构关系,类图是个好的工具,我已经画出来了,请看。

其中,带减号“-”的表示是private的,加号“+”的表示是public的。我们可以发现Terrorist和两个枪支类Rifle以及Pistol是一种依赖关系。那么这样实现我们的控制台版的CS游戏好不好呢?Absolutely不好!!!假如,游戏上线1个月,我们需要更新枪支来吸引新老玩家,我们想要增添一款狙击步枪AWP。好吧,我是一个OO程序员,这难不倒我,我只需要添加一个AWP类:

public class AWP
{
public void Shoot()
{
 Console.WriteLine("AWP开始射击:啪。一枪毙敌");
}
} 

然后我们需要修改下Terrorist类,添加一个private字段AWP,然后修改SetGun()方法,我们需要让if…else变的更长。接下来,还要修改KillEnemy。还是if…else。。。假如,又过了一个月,我们又想添加一款冲锋枪M4A1。那么,添加类,修改Terrorist。假如,又过了一个月。。。。。Ohmygodness!!!你杀了我吧。你会发现,你的代码在不停的修改,如果哪一款枪械决定删除了,简直要被逼疯了。那么,好吧,我决定使用抽象类试试方法2思考上一个方法,我们的麻烦来自于哪里呢?来自于每一种枪械都是一个单独的类,她们之间没有任何关联关系,这就使得我们匪徒类Terrorist必须有各个枪械类型的引用字段,但是。。业务要求Terrorist一次只能用一支枪。那么,如。果我们能用一个字段来保留这些枪支的引用就好了。我们设计一个抽象的抢类, 让所有的枪械都继承于这个抽象的枪类 本着这个思路,我们先画一张新方法的类图。

接下来就是代码实现了。我们先来设计抽象类 AbstractGun。

public abstract class AbstractGun
{
public abstract void Shoot();
} 

这里代码非常简单,抽象类AbastractGun只有一个抽象方法Shoot()。所有的枪支类型,都要继承于此抽象类。比如Rifle类

public class Rifle:AbstractGun
{
public override void Shoot()
{
Console.WriteLine("步枪开始射击:哒哒哒。。");
}
} 

这里的每一个子类,都必须override抽象类的Shoot()方法。(这是C#抽象类的语法要求,不懂的拖出去扁。。。)。下面Terrorist类就简单了。

public class Terrorist
{
private AbstractGun gun;
public Terrorist()
{
}
public void SetGun(AbstractGun gun)
{
this.gun = gun;
}
public void KillEnemy()
 {
gun.Shoot();
}
} 

再也没有烦人的if…else了,整个世界清静了。。。那么下边开始游戏,new一个拉登

class Program
{
static void Main(string[] args)
{
TerroristlaDeng=newTerrorist();//new出来一个拉登
laDeng.SetGun(newPistol());//给他一支*枪
laDeng.KillEnemy();//拉登开枪
laDeng.SetGun(newRifle());
laDeng.KillEnemy();
}
} 

如果,哪一天,你需要添加一种枪械叫机机关枪(▄【┳═一)。。。那么, 你只需要再写一个机关枪的类

public class MachineGun:AbstractGun
{
public override void Shoot()
{
Console.WriteLine("机关枪开始射击:突突突。");
}
} 

这时候,你会发现,Terrorist的代码根本无需改动,因为,他需要的枪的字段只是一个抽象的。好了,前台立刻可以使用MachineGun了。

laDeng.SetGun(newMachineGun());
laDeng.KillEnemy();

好了,通过这个例子,我想你已经懂得C#抽象类的使用了。需要注意的是:
1、抽象类只能被继承,不能实例化,比如你要是想SetGun(newAbstracGun())那就不行。
2、抽象类中可以包含抽象成员,也可以包含非抽象成员。
3、但是抽象成员只能出现在抽象类中
4、抽象方法不能有方法体语句,这单类似于接口,但是接口不能有可访问性修饰符。
5、抽象方法也可以有参数列表
6、如果子类不是抽象类,那么子类必须重写(override)抽象方法
7、子类必须实现父类(抽象类)的所有抽象方法。

时间: 2024-10-09 22:37:56

实例详解C#抽象类及其用法(转)的相关文章

PHP中__get()和__set()的用法实例详解

PHP中__get()和__set()的用法实例详解 在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属性,对每个字段进行set和get的操作.只需要加上两个魔术方法即可 php面向对象_get(),_set()的用法 一般来说,总是把类的属性定义为private,这更符合 现实的逻辑.但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属 性.类似于java中的javabean的操作,

C#中string用法实例详解

在进行C#程序设计时,用的最多的莫过于string了,但有些时候由于不仔细或者基础的不牢固等因素容易出错,今天本文就来较为详细的总结一下C#中string的用法.具体如下: 1.string是一个引用类型,平时我们比较string对象,比较的是对象的值而不是对象本身 如下面代码所示: string strA="abcde"; string strB="abc"; string strC="de"; Console.WriteLine(strA =

C#泛型Dictionary的用法实例详解

本文以实例形式讲述了C#中的泛型Dictionary的用法.具有很好的实用价值.分享给大家供大家参考.具体如下: 泛型最常见的用途是泛型集合,命名空间System.Collections.Generic 中包含了一些基于泛型的集合类,使用泛型集合类可以提供更高的类型安全性,还有更高的性能,避免了非泛型集合的重复的装箱和拆箱. 很多非泛型集合类都有对应的泛型集合类,下面是常用的非泛型集合类以及对应的泛型集合类: 非泛型集合类 泛型集合类 ArrayList List<T> HashTable D

C#的FileSystemWatcher用法实例详解

本文实例详述了C#的FileSystemWatcher用法.分享给大家供大家参考.具体用法如下: FileSystemWatcher控件主要功能: 监控指定文件或目录的文件的创建.删除.改动.重命名等活动.可以动态地定义需要监控的文件类型及文件属性改动的类型. 1.常用的几个基本属性: (1) Path :设置要监视的目录的路径. (2) IncludeSubdirectories :设置是否级联监视指定路径中的子目录. (3) Filter :设置筛选字符串,用于确定在目录中监视哪些类型的文件

实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化(一)

在数据库有外键的时候,使用 select_related() 和 prefetch_related() 可以很好的减少数据库请求的次数,从而提高性能.本文通过一个简单的例子详解这两个函数的作用.虽然QuerySet的文档中已经详细说明了,但本文试图从QuerySet触发的SQL语句来分析工作方式,从而进一步了解Django具体的运作方式. 本来打算写成一篇单独的文章的,但是写完select_related()之后发现长度已经有点长了,所以还是写成系列,大概在两到三篇.整个完成之后将会在这里添加上

Spring基于事件驱动模型的订阅发布模式代码实例详解

代码下载地址:http://www.zuidaima.com/share/1791499571923968.htm 原文:Spring基于事件驱动模型的订阅发布模式代码实例详解 事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理解它的几个关键点: 首先是一种对象间的一对多的关系:最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方): 当目标发送改变(发布),观察者(订阅者)就可以接收到改变: 观察者如何处理(如行人如何走,是快走/慢走/不走,目标不会管的

php扩展imagick实例详解

imagick是一个可以供PHP调用ImageMagick功能的PHP扩展.使用这个扩展可以使PHP具备和ImageMagick相同的功能. PHP建图通常都用GD库,因为是内置的不需要在服务器上额外安装插件,所以用起来比较省心,但是如果你的程序主要的功能就是处理图像,那麼就不建议用GD了,因为GD不但低效能而且能力也比较弱,佔用的系统资源也颇多,另外GD的creatfrom也有bug,而imagick却是一个很好的替代品,为此最近把我的一个项目由GD改成了imagick,但是改完之后出现了一些

免费的HTML5连载来了《HTML5网页开发实例详解》连载(三)DOCTYPE和字符集

在2.1.2节中通过新老DOCTYPE的对比,读者可以清晰地看到HTML 5在精简旧有结构上做出的努力.DOCTYPE在出现之初主要用于XML中,用作描述XML允许使用的元素.属性和排列方式.起初HTML借鉴了XML中DOCTYPE的使用方法,并赋予了新用法,如大家熟知的触发浏览器的标准模式.假使在制作一张页面时,没有设定DOCTYPE,则浏览器会以怪异模式状态进行处理(即Quirks模式),该模式与标准模式在盒模型.样式.布局等都存在较大差异.因此,DOCTYPE在制作页面时是不可或缺的部分.

C# Oracle数据库操作类实例详解

本文所述为C#实现的Oracle数据库操作类,可执行超多常用的Oracle数据库操作,包含了基础数据库连接.关闭连接.输出记录集.执行Sql语句,返回带分页功能的dataset .取表里字段的类型和长度等,同时还有哈稀表自动插入数据库等高级任务.需要特别指出的是:在执行SQL语句,返回 DataReader之前一定要先用.read()打开,然后才能读到数据,再用hashTable对数据库进行insert,update,del操作,注意此时只能用默认的数据库连接"connstr". 本文