与中职生探讨面向对象程序设计——C#

2009-11-17 09:04周玉凤
中国校外教育(下旬) 2009年13期
关键词:音频文件视频文件数据类型

周玉凤

[摘 要]:2005年初,笔者在北京参加了北大青鸟教师培训班,学习的内容是C#。之后,经过几年的教学实践,笔者对面向对象程序设计有了更为深广的理解,本文笔者就谈谈自己的认识与体会,以与中职计算机专业学生朋友交流。

[关键词]:中职生 面向对象程序设计 C#

首先,笔者谈几点理解面向对象程序设计的要点:

封装性:数据和行为封装在一个自定义的数据类型里面,其作用:(1)把松散的方法聚合到数据类型里面。(2)隐藏数据类型内部的数据定义。

继承性:把多个数据类型按照一定的方法进行抽象,把共有的属性放的一个高层的数据类型里面,然后底层的多个类型可以共享这个高层类型的数据和方法。作用有两个:(1)简化数据类型的定义,减少重复定义。(2)使组织结构清晰化,这和现实世界的分门别类具有异曲同工之妙。

多态性:一个方法,可以根据其操纵的具体类型的对象的不同(抽象类型相同),可以有不同的表现。其作用:(1)进一步简化方法的定义。(2)是多种不同的方法具有统一的接口,方便调用。

接下来,我们结合实例说说设计模式。

为了更好地理解设计思想,实例尽可能简单化。但随着需求的增加,程序将越来越复杂。此时,就有修改设计的必要,重构和设计模式就可以派上用场了。最后当设计渐趋完美后,你会发现,即使需求不断增加,你也可以神清气闲,不用为代码设计而烦恼了。

假定我们要设计一个媒体播放器。该媒体播放器目前只支持音频文件mp3和wav。如果不谈设计,设计出来的播放器可能很简单:

public class MediaPlayer

{

private void PlayMp3()

{

MessageBox.Show("Play the mp3 file.");

}

private void PlayWav()

{

MessageBox.Show("Play the wav file.");

}

public void Play(string audioType)

{

switch (audioType.ToLower())

{

case ("mp3"):

PlayMp3();

break;

case ("wav"):

PlayWav();

break;

}

}

}

你会发现,这个设计有很大的隐患,它根本没有为未来的需求变更提供最起码的扩展。仔细分析这段代码,它其实是一种最古老的面向结构的设计。如果你要播放的不仅仅是mp3和wav,你会不断地增加相应地播放方法,然后让switch子句越来越长,直至达到你视线看不到的地步。

我们来体验面向对象的思想。把mp3和wav看作是一个独立的对象。

public class MP3

{

public void Play()

{

MessageBox.Show("Play the mp3 file.");

}

}

public class WAV

{

public void Play()

{

MessageBox.Show("Play the wav file.");

}

}

统一的Play()方法。在后面的设计中,会发现这样改名是很关键的!

但以现在的方式去更改MediaPlayer的代码,实质并没有多大的变化。

既然mp3和wav都属于音频文件,他们都具有音频文件的共性,我们就应该建立一个共同的父类。

public class AudioMedia

{

public void Play()

{

MessageBox.Show("Play the AudioMedia file.");

}

}

现在,我们引入了继承的思想。

我们播放的只会是某种具体类型的音频文件,因此,这个AudioMedia类并没有实际使用的情况。对应在设计中,就是:这个类永远不会被实例化。所以,还得动一下手术,将其改为抽象类。

public abstract class AudioMedia

{

public abstract void Play();

}

public class MP3:AudioMedia

{

public override void Play()

{

MessageBox.Show("Play the mp3 file.");

}

}

public class WAV:AudioMedia

{

public override void Play()

{

MessageBox.Show("Play the wav file.");

}

}

public class MediaPlayer

{

public void Play(AudioMedia media)

{

media.Play();

}

}

看看现在的设计,既满足了类之间的层次关系,同时又保证了类的最小化原则,更利于扩展(到这里,你会发现play方法名改得多有必要)。

即使你现在又增加了对WMA文件的播放,只需要设计WMA类,并继承AudioMedia,重写Play方法就可以了,MediaPlayer类对象的Play方法根本不用改变。

然而,如果要求设计的媒体播放器能够支持视频文件。怎么办呢?

原来的软件设计结构似乎出了问题,视频文件和音频文件有很多不同的地方。解决起来也不难,让视频文件对象认音频文件作父亲啊。需要为视频文件设计另外的类对象,假设我们支持RM和MPEG格式的视频:

public abstract class VideoMedia

{

public abstract void Play();

}

public class RM:VideoMedia

{

public override void Play()

{

MessageBox.Show("Play the rm file.");

}

}

public class MPEG:VideoMedia

{

public override void Play()

{

MessageBox.Show("Play the mpeg file.");

}

}

虽然视频和音频格式不同,别忘了,他们都是媒体中的一种,很多时候,他们有许多相似的功能,比如播放。根据接口的定义,完全可以将相同功能的一系列对象实现同一个接口:

public interface IMedia

{

void Play();

}

public abstract class AudioMedia:IMedia

{

public abstract void Play();

}

public abstract class VideoMedia:IMedia

{

public abstract void Play();

}

再更改一下MediaPlayer的设计就OK了:

public class MediaPlayer

{

public void Play(IMedia media)

{

media.Play();

}

}

总结一下,从MediaPlayer类的演变,我们可以得出这样一个结论:在调用类对象的属性和方法时,尽量避免将具体类对象作为传递参数,而应传递其抽象对象,更好地是传递接口,将实际的调用和具体对象完全剥离开,这样可以提高代码的灵活性。

猜你喜欢
音频文件视频文件数据类型
流媒体视频文件相似性识别的方法
详谈Java中的基本数据类型与引用数据类型
随心定制视频文件的缩略图
如何理解数据结构中的抽象数据类型
基于Android手机的音频文件取证技术研究
基于SeisBase模型的地震勘探成果数据管理系统设计
提取APP中的音频文件
数字水印在音频文件篡改检测中的应用
视频网格中自适应热度变化的条块化存储
范畴数据类型上的子类型*