设计模式学习笔记(一)——面向对象设计模式与原则.doc
《设计模式学习笔记(一)——面向对象设计模式与原则.doc》由会员分享,可在线阅读,更多相关《设计模式学习笔记(一)——面向对象设计模式与原则.doc(23页珍藏版)》请在沃文网上搜索。
1、设计模式学习笔记(一)面向对象设计模式与原则 今天听了C#面向对象设计模式纵横谈(1):面向对象设计模式与原则课程。总结了一些笔记。首先介绍了什么是设计模式:设计模式描述了软件设计过程中某一类常见问题的一般性的解决方案。下面主要讨论面向对象设计模式。面向对象设计模式描述了类与相互通信的对象之间的组织关系。目的是应对变化、提高复用、减少改变。那到底什么是对象:1、从概念层面讲,对象是某种拥有职责的抽象;2、从规格层面讲,对象是一系列可以被其他对象使用的公共接口;3、从语言实现层面来看,对象封装了代码和数据(也就是行为和状态)。对于这三点,我理解最深的应该是第三点。这可能和我把大多精力放在了代码实
2、现上有关,然而忽略了编程的的思想。如果我们抛开代码的实现来看对象的概念,那么它应该就像一个具体的物体,比如说:榔头,从概念层面讲,榔头有它的职责,也就是它是做什么用的(用来砸钉子,当然还会有其他用途,如防身),从规格层面讲,比如人使用榔头砸钉子。面向对象的设计模式有三大原则:1、这对接口编程,而不是针对实现编程。在知道设计模式之前,我对接口的出现很不理解。不明白为什么这个什么都不能实现的东西会存在,当然,也对多态表示茫然。实际上我是还没有理解面向对象编程的思想。在对设计模式略有了解后发现接口的确是一个好东西,用它实现多态的确减少了代码的修改。比如说在Head First Design Patt
3、erns中有一个例子,说一个有关鸭子的游戏。游戏当中有很多种的鸭子,如:野鸭,木头鸭,鸭子模型。我们首先会想到做一个抽象类:abstract class Duck,Duck当中有很多的抽象属性和方法,如quack。我们用子类继承的时候都会实例化这个方法。public abstract class Duckpublic abstract void quack()public class MallardDuck:Duckpublic override void quack()Console.Write(I can quack);当程序成型后,我们有了很多种鸭子,突然,我们发现有的鸭子会飞,我们会在
4、Duck中在加上一个抽象方法abstract void fly();于是我们不得不在所有的子类当中添加fly的实现,有人会说,如果我们在Duck中直接添加fly的实现,不久不用在子类中添加实现了吗?那老板就该问你:你见过木头鸭子满天飞(哦,天啊!木头鸭子也飞起来了,这是什么世界!)。对不起老板,现在咱们都见到了。这时我们换一种想法,如果我们把这些方法都提取出来,把它变成Duck的成员,好像问题就会简单些。哈哈,好像扯的有点远了,现在回来接着记我的笔记。2、优先使用对象组合,而不是类的继承。这就使说多使用“has a”,少使用“is a”,哈哈,我又想说回刚才的例子。换个角度考虑Duck及其功能
5、,我们设计一个fly的接口和一些具体的飞行方法。public interface FlyBehaviorvoid fly();public class FlyWithWing:FlyBehaviorpublic void fly()Console.Write(I can flyn);public class FlyNoWay:FlyBehaviorpublic void fly()Console.Write(I cant flyn); 好了,对于Duck来说,现在它应该有一个(has a)fly的方法public abstract class Duckpublic Duck()public F
6、lyBehavior flybehavior; 现在我们再来实现两种鸭子public class ModelDuck:Duckpublic ModelDuck()flybehavior = new FlyNoWay();public class MallardDuck:Duckpublic MallardDuck()flybehavior = new FlyWithWing();这样如果要是在加上某种行为的话,我们就不必在每一种鸭子上下功夫。把注意力放在我们关心的鸭子品种上(别太使劲关注,小心禽流感,“阿切!”)。3、封装变化点,实现松耦合,这点不用多说了。课程中提到,编码当中的设计模式使用不
7、是我们在编程之初就定下来的,应该是重构得到设计模式(Refactoring to Patterns)。哦,原来是这样,也好理解。在编码中遇到问题,然后想想应对方式。哈哈,我原来认为开始编程时就指定我们用什么设计模式呢。下面说说设计原则:1、单一职责原则(SRP):一个类应仅有一个引起它变化的原因。2、开放封闭原则(OCP):类模块应可扩展,不可修改。这里要说明一下,扩展和修改是不同的。比如:我们要在加一种ModelDuck,那么我们写一个ModelDuck的类继承Duck,这叫扩展,不是修改。什么是修改,就好像我们开始说的那种作法,为了加一个fly的功能,我们要把所有的子类中加入不同的实现,这
8、叫修改。3、Liskov替换原则:子类可替换基类。4、依赖倒置原则:高层模块不依赖于低层模块,二者都依赖于抽象。还是刚才的例子:Duck是一个高层模块,fly是低层模块。Duck不依赖于fly,高层模块的改变慢,而低层模块的改变慢。抽象不应依赖于实现细节,实现细节应依赖于抽象。fly是一个抽象,它不依赖如何飞行。5、接口隔离原则:不强迫客户程序依赖于它们不用的方法(有道理,木头鸭子不会飞为什么要让它实现飞的功能。)最后有人提问接口和抽象类的区别:接口可以多继承,抽象类只能但继承。接口定义组件间的合同。使用抽象类为一个is a的关系。设计模式学习笔记(二)Singleton单件模式 这是我写模式
9、设计的第二篇,首先来说说设计模式的分类。基本的23种设计模式从目的上可分为三种:1、 创建型(Creational)模式:负责对象创建。2、 结构型(Structural)模式:处理类与对象间的组合,可以解决一些继承依赖性的问题3、 行为型(Behavioral)模式:类与对象交互中的职责分配,可以解决组件间如何和交互,隔离变化。下面来说说单件模式:首先说说单件模式产生的动机,也就是为什么会出现单件模式。有一些类在系统中只存在一个实例才能确保他们的逻辑正确性以及良好的效率。这时我想到我遇到的一个问题。我曾经遇到一个WinForm程序,运行后出现一个登陆框,输入用户名密码后点击登陆,然后显示一个
10、登陆后的界面。但是点击登陆后,程序要做一些操作,由于这段操作用时相对较长,在不经意时,我有点击了一次登陆按钮,最后出现了两个对话框。如:我现在有两个Form窗体Form1和Form2。Form1上有一个按钮用来打开Form2并隐藏自己。我们可以这样写:private void button1_Click(object sender, System.EventArgs e)Form2 form = new Form2();form.Show();this.Hide();如果我们在显示Form2前由一些比较耗时的操作。如:我们让线程的沉睡10秒在显示Form2,当我们在线程沉睡时继续点击Form1
11、上的Button,有可能就会出现两个Form2的窗体。(我试过可以出现两个Form2,如果你有心试但没事出来别拿西红柿砍我,哈哈)private void button1_Click(object sender, System.EventArgs e)Thread.Sleep(10000);Form2 form = new Form2();form.Show();this.Hide();这种情况出现不能怪客户多点了一下,也不能说是编译器不够智能,应该是我们程序上的Bug,我想这种情况用单件模式应该可以解决。单件模式的使用意图就是:保证一个类仅有一个实例,并提供一个该实例全局的访问点(这句话当然
12、不是我先说的,是引用Gof在设计模式中的一句话)那类的设计者如何绕过常规的构造器来实现单件模式呢?下面就来谈谈单件模式的实现。单件模式在结构上使用了景泰方法来约束构造器(也就是构造函数)创建对象。在单线程的情况下:私有化构造函数,使类的使用者调用不到这个构造函数来new一个实例。类型中可以自己new一个实例。类中创建一个静态私有变量和Static公有属性。在公有属性中实现此类的实例化。这样在第一次请求时创建此对象。代码如下:class Singletonprivate static Singleton _instance;private Singleton()public static Sin
13、gleton f_Instancegetif(_instance = null)_instance = new Singleton();return _instance;我在main函数中写入如下程序来查看一下这样写是否有效:static void Main(string args)Singleton t1 = Singleton.f_Instance;Singleton t2 = Singleton.f_Instance;Console.Write(object.ReferenceEquals(t1,t2);Console.Read();控制台显示为True,开来还是有效的。当然在Main中
14、我也试过这样写:Singleton t1 = new Singleton(),编译时告诉我Singleton()不可访问(当然,人家是私有的,不是自家人当然不见)这种单线程下的单件模式有几点要注意:1、 构造器私有化(如果要此类被继承,可以用protected声明构造器)2、 不要支持IClinieable接口,因为会导致多个对象实例的出现3、 不能支持序列化4、 单件模式只考虑了对象创建的管理,没有考虑对象的销毁管理(创建自己的对象,销毁的事交给垃圾回收器吧)5、 不能应对多线程环境,因为会导致多个对象实例的出现那在多线程下如何实现呢?代码如下:class SingletonMuli/多线程
15、Singleton模式private static volatile SingletonMuli _instance;/volatile是为了让编译器对此代码编译后的位置不进行调整private SingletonMuli()private static object lockHelper = new object();/辅助器,不参与对象构建public static SingletonMuli f_Instancegetif(_instance = null)lock(lockHelper)if(_instance = null)/双检查_instance = new SingletonM
16、uli();return _instance;当然还有一些更简单的实现方法,如:class Singleton1/可以用在多线程环境public static readonly Singleton1 _instance = new Singleton1();private Singleton1()其中要提到的是在_instance私有字段的实例化叫做“内联初始化”。内联初始化是指在声明时。实际上面的代码上相当于如下代码:Public static readonly Singleton1 _instance;Static Singleton()/静态构造函数_instance = new Sin
17、gleton();/私有构造器Private Singleton()内联初始化时会先执行静态构造器,如果没有静态构造函数,系统会默认一个。在访问此静态字段时执行静态构造器生成。静态构造器保证了在多线程时只有一个线程执行,自动加锁。当然,第二种实现方式也有一些缺点,如:静态构造器必须是私有的、无参的。不过也可以用其他的方式解决这类问题。如可以用方法属性实现扩展或修改私有构造器。现在我们可以回来看看我开始说的那两个Form的问题,我们现在可以这样实现:private static Form2 form;private void button1_Click(object sender, System
18、.EventArgs e)Thread.Sleep(10000);object lockhelp = new object();if(form = null)lock(lockhelp)if(form = null)form = new Form2();form.Show();this.Hide();这样问题就解决了(我是没有点出来第二个Form2,如果那位点出来了,给我发Email,我请她/他在天津的烤鸭)单件模式实际上是利用控制对象创造过程来控制对象的创造个数的方法,我们可以对其进行扩展,不是让他只生成一个对象,可以让他只生成几个对象,这样可以实现对象池。单件模式的核心是:如何控制用户使用
19、new对一个类的实例构造器的任意调用。设计模式学习笔记(三)Abstract Factory抽象工厂模式 抽象工厂是一种创建型模式,是为了解决实例化时所带来的问题。我们先来看看是什么问题,有的时候我们会遇到这种情况,我们需要一系列的对象。举个例子,有一系列BMW汽车零部件的对象:轮子bmwwheel,油箱bmwoilbox,在一个管理函数中调用它们,代码如下class BMWWheelpublic BMWWheel(); class BMWOilboxpublic BMWOilbox();public void Manage()BMWOilbox oilbox = new BMWOilbox(
20、);BMWWheel wheel = new BMWWheel();如果现在需求变了,我们要用大众一汽BORA的零件,不用BMW的,那么我们除了要再加上相应的零件对象外还要将Manage函数中的对象更改为BORA的零件对象。那这时发现new会带来了一些问题:实现依赖,不能应对具体实例化类型的变化。如何解决这类问题呢?封装变化点。(没有变化的就不需要封装)工厂模式的缘起:1、变化点在“对象创建”,因此就封装“对象创建”2、面向接口编程简单工厂问题:1、不能应对“不同系列对象”的变化。如:我们要在上面的代码中加上其他的对象就不能很好的应对了2、使用面向对象国内的技术来封装变化点动机:在软件系统中,
21、经常面临着“一系列相互依赖的对象”的创建工作;同时,由于需求的变化,往往存在更多系列对象的创建工作。面对这种问题,我们想绕过常规的对象创建方法,提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合。对于“紧耦合”,我原来是不喜欢这个词的,但是今天明白了,不是程序紧耦合不好,而是面对频繁变化的需求,紧耦合会使程序的编写变得很吃力。如果面对一个不变的需求,松耦合和紧耦合在代码编写上应该是没什么区别的。设计模式中解释这种模式的意图是:提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定他们的具体类。下面我们来看看如何使用抽象工厂模式完成对这种变化的封装:首先
- 1.请仔细阅读文档,确保文档完整性,对于不预览、不比对内容而直接下载带来的问题本站不予受理。
- 2.下载的文档,不会出现我们的网址水印。
- 3、该文档所得收入(下载+内容+预览)归上传者、原创作者;如果您是本文档原作者,请点此认领!既往收益都归您。
下载文档到电脑,查找使用更方便
10 积分
下载 | 加入VIP,下载更划算! |
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 设计 模式 学习 笔记 面向 对象 原则