/**/ /************************************************** * 为了更好的理解OOP思想,我们先看一个例子(例1): *假设要设计一个媒体播放器,应播放器支持音频文件MP3和WAV**************************************************/ // 例1 namespace OOP思想 ... { public partial class Form1 : Form ...{ public Form1() ...{ InitializeComponent(); } private void btnPlay_Click(object sender, EventArgs e) ...{ PlayMP3(); //播放MP3 //PlayWAV(); //播放WAV } public void PlayMP3() ...{ MessageBox.Show("开始播放MP3..."); } public void PlayWAV() ...{ MessageBox.Show("开始播放WAV..."); } } } // 例2 /**/ /************************************************** * 自然,你会发现这是相当糟糕的设计,因为它根本没有为未来 * 需要的变更提供最起码的扩展.根据OOP的思想,我们应该把MP3 * 和WAV看成一个独立的对象.请看例2**************************************************/ namespace OOP思想 ... { public partial class Form1 : Form ...{ public Form1() ...{ InitializeComponent(); } private void btnPlay_Click(object sender, EventArgs e) ...{ IMedia im = new WAV(); //见注1 im.Play(); } } interface IMedia //多媒体接口 ...{ void Play(); } public class MP3:IMedia //MP3类 ...{ public void Play() ...{ MessageBox.Show("开始播放MP3..."); } } public class WAV: IMedia //WAV类 ...{ public void Play() ...{ MessageBox.Show("开始播放WAV..."); } }} /**/ /************************************************** * 如果看懂例2、例3,好...恭喜你,你已经不知不觉中应用了重构的 * 方法了,但似乎并没有命中要害,实质没有多大变化.请看例4**************************************************/ // 例3 namespace OOP思想 ... { public partial class Form1 : Form ...{ public Form1() ...{ InitializeComponent(); } private void btnPlay_Click(object sender, EventArgs e) ...{ AudioMedia am = new WAV(); //见注1 am.Play(); } } public abstract class AudioMedia //音频抽象类 ...{ public abstract void Play(); } public class MP3 : AudioMedia //MP3类 ...{ public override void Play() ...{ MessageBox.Show("开始播放MP3..."); } } public class WAV : AudioMedia //WAV类 ...{ public override void Play() ...{ MessageBox.Show("开始播放WAV..."); } }} /**/ /************************************************** * 注1 * 在调用类对象的属性和方法时,尽量避免使用具体类对象,而 * 是应传递其抽象对象,更好的是传递接口。 * * 例2 例3表达的意思是一样的,只不过分别使用的是接口和抽象类**************************************************/ /**/ /************************************************** * 是不是至此就该画上句号了呢?然而客户永远不会满足的,他 * 们在抱怨这个播放器了,因为它只能听到声音而看不到画面.好,让 * 我们继续为它加上视频的功能吧.见例4**************************************************/ // 例4 namespace OOP思想 ... { public partial class Form1 : Form ...{ public Form1() ...{ InitializeComponent(); } private void btnPlay_Click(object sender, EventArgs e) ...{ Media m = new Media(); IMedia im = new RM(); m.Play(im); } } public interface IMedia //多媒体接口 见注2 ...{ void Play(); } public abstract class aAudioMedia:IMedia //音频抽象类 ...{ public abstract void Play(); } public class MP3 : aAudioMedia //MP3类 ...{ public override void Play() ...{ MessageBox.Show("开始播放MP3..."); } } public class WAV : aAudioMedia //WAV类 ...{ public override void Play() ...{ MessageBox.Show("开始播放WAV..."); } } public abstract class aVideoMedia:IMedia //视频抽象类 ...{ public abstract void Play(); } public class RM : aVideoMedia //RM类 ...{ public override void Play() ...{ MessageBox.Show("开始播放RM..."); } } public class MPEG : aVideoMedia //MPEG类 ...{ public override void Play() ...{ MessageBox.Show("开始播放MPEG..."); } } public class Media ...{ public void Play(IMedia im) ...{ im.Play(); } }} /**/ /************************************************** * 我省略了一个只使用抽象类的例子,如果此例只使用抽象类 * 的放,你会发现,你就无法通用Media这个类了. * * 注2 * 接口+抽象类的混合使用 * * 例3 例4表达的意思是一样的,只不过分别使用的是接口和抽象类 * 你也可以不使用抽象类,使用它只是更准确表达OOP思想. 见例5**************************************************/ // 例5 namespace OOP思想 ... { public partial class Form1 : Form ...{ public Form1() ...{ InitializeComponent(); } private void btnPlay_Click(object sender, EventArgs e) ...{ IMedia im = new RM(); Media m = new Media(); m.Play(im); } } public interface IMedia //多媒体接口 ...{ void Play(); } public class MP3 : IMedia //MP3类 ...{ public void Play() ...{ MessageBox.Show("开始播放MP3..."); } } public class WAV : IMedia //WAV类 ...{ public void Play() ...{ MessageBox.Show("开始播放WAV..."); } } public class RM : IMedia //RM类 ...{ public void Play() ...{ MessageBox.Show("开始播放RM..."); } } public class MPEG : IMedia //MPEG类 ...{ public void Play() ...{ MessageBox.Show("开始播放MPEG..."); } } public class Media ...{ public void Play(IMedia im) ...{ im.Play(); } }} // 例6 /**/ /************************************************** * 工厂模式: * 使用工厂模式之后,回过头来看看,Media这个类不需要了.两 * 个抽象类aVideoMedia 和 aAudioMedia也不需要了.现在你应该 * 体会到IMedia的好处了. * 使用接口有什么好处?那就是你的主程序在没有具体业务类 * 的时候,同样可以编译通过.因此,即使你增加了新的业务类,你的 * 主程序也是不用改动的. * * 工厂模式仍需深刻体会!!!!!!**************************************************/ namespace OOP思想 ... { public partial class Form1 : Form ...{ public Form1() ...{ InitializeComponent(); } private void btnPlay_Click(object sender, EventArgs e) ...{ IMediaFactory fac = new MP3MediaFactory(); //为MP3工厂规划一块地 IMedia im = fac.CreateMedia(); //建议一座MP3工厂 im.Play(); //MP3工厂运转 } } public interface IMedia //多媒体接口 ...{ void Play(); } public interface IMediaFactory //多媒体工厂接口 ...{ IMedia CreateMedia(); } public class MP3MediaFactory : IMediaFactory //MP3工厂类 ...{ public IMedia CreateMedia() ...{ return new MP3(); } } public class WAVMediaFactory : IMediaFactory //WAV工厂类 ...{ public IMedia CreateMedia() ...{ return new WAV(); } } public class MP3 : IMedia //MP3类 ...{ public void Play() ...{ MessageBox.Show("开始播放MP3..."); } } public class WAV : IMedia //WAV类 ...{ public void Play() ...{ MessageBox.Show("开始播放WAV..."); } } public class Media ...{ public void Play(IMedia im) ...{ im.Play(); } }}