设计模式学习笔记(一)——面向对象设计模式与原则

来源:百度文库 编辑:16楼社区 时间:2021/04/15 21:56:32
设计模式学习笔记(一)——面向对象设计模式与原则
今天听了《C#面向对象设计模式纵横谈(1):面向对象设计模式与原则》课程。总结了一些笔记。
首先介绍了什么是设计模式:设计模式描述了软件设计过程中某一类常见问题的一般性的解决方案。
下面主要讨论面向对象设计模式。
面向对象设计模式描述了类与相互通信的对象之间的组织关系。目的是应对变化、提高复用、减少改变。
那到底什么是对象:
1、从概念层面讲,对象是某种拥有职责的抽象;
2、从规格层面讲,对象是一系列可以被其他对象使用的公共接口;
3、从语言实现层面来看,对象封装了代码和数据(也就是行为和状态)。
对于这三点,我理解最深的应该是第三点。这可能和我把大多精力放在了代码实现上有关,然而忽略了编程的的思想。如果我们抛开代码的实现来看对象的概念,那么它应该就像一个具体的物体,比如说:榔头,从概念层面讲,榔头有它的职责,也就是它是做什么用的(用来砸钉子,当然还会有其他用途,如防身),从规格层面讲,比如人使用榔头砸钉子。
面向对象的设计模式有三大原则:
1、这对接口编程,而不是针对实现编程。在知道设计模式之前,我对接口的出现很不理解。不明白为什么这个什么都不能实现的东西会存在,当然,也对多态表示茫然。实际上我是还没有理解面向对象编程的思想。在对设计模式略有了解后发现接口的确是一个好东西,用它实现多态的确减少了代码的修改。
比如说在《Head First Design Patterns》中有一个例子,说一个有关鸭子的游戏。游戏当中有很多种的鸭子,如:野鸭,木头鸭,鸭子模型。我们首先会想到做一个抽象类: abstract class Duck,Duck当中有很多的抽象属性和方法,如quack。我们用子类继承的时候都会实例化这个方法。
public abstract class Duck
{
public abstract void quack()
}
public class MallardDuck:Duck
{
public override void quack()
{
Console.Write("I can quack");
}
}
当程序成型后,我们有了很多种鸭子,突然,我们发现有的鸭子会飞,我们会在Duck中在加上一个抽象方法abstract void fly();于是我们不得不在所有的子类当中添加fly的实现,有人会说,如果我们在Duck中直接添加fly的实现,不久不用在子类中添加实现了吗?那老板就该问你:你见过木头鸭子满天飞(哦,天啊!木头鸭子也飞起来了,这是什么世界!)。对不起老板,现在咱们都见到了。
这时我们换一种想法,如果我们把这些方法都提取出来,把它变成Duck的成员,好像问题就会简单些。
哈哈,好像扯的有点远了,现在回来接着记我的笔记。
2、优先使用对象组合,而不是类的继承。
这就使说多使用“has a”,少使用“is a”,哈哈,我又想说回刚才的例子。换个角度考虑Duck及其功能,我们设计一个fly的接口和一些具体的飞行方法。
public interface FlyBehavior
{
void fly();
}
public class FlyWithWing:FlyBehavior
{
public void fly()
{
Console.Write("I can fly\n");
}
}
public class FlyNoWay:FlyBehavior
{
public void fly()
{
Console.Write("I can‘t fly\n");
}
}
好了,对于Duck来说,现在它应该有一个(has a)fly的方法
public abstract class Duck
{
public Duck()
{}
public FlyBehavior flybehavior;
}
现在我们再来实现两种鸭子
public class ModelDuck:Duck
{
public ModelDuck()
{
flybehavior = new FlyNoWay();
}
}
public class MallardDuck:Duck
{
public MallardDuck()
{
flybehavior = new FlyWithWing();
}
}
这样如果要是在加上某种行为的话,我们就不必在每一种鸭子上下功夫。把注意力放在我们关心的鸭子品种上(别太使劲关注,小心禽流感,“阿切!”)。
3、封装变化点,实现松耦合,这点不用多说了。
课程中提到,编码当中的设计模式使用不是我们在编程之初就定下来的,应该是重构得到设计模式(Refactoring to Patterns)。哦,原来是这样,也好理解。在编码中遇到问题,然后想想应对方式。哈哈,我原来认为开始编程时就指定我们用什么设计模式呢。
下面说说设计原则:
1、单一职责原则(SRP):一个类应仅有一个引起它变化的原因。
2、开放封闭原则(OCP):类模块应可扩展,不可修改。这里要说明一下,扩展和修改是不同的。比如:我们要在加一种ModelDuck,那么我们写一个 ModelDuck的类继承Duck,这叫扩展,不是修改。什么是修改,就好像我们开始说的那种作法,为了加一个fly的功能,我们要把所有的子类中加入不同的实现,这叫修改。
3、Liskov替换原则:子类可替换基类。
4、依赖倒置原则:高层模块不依赖于低层模块,二者都依赖于抽象。还是刚才的例子:Duck是一个高层模块,fly是低层模块。Duck不依赖于fly,高层模块的改变慢,而低层模块的改变慢。
抽象不应依赖于实现细节,实现细节应依赖于抽象。fly是一个抽象,它不依赖如何飞行。
5、接口隔离原则:不强迫客户程序依赖于它们不用的方法(有道理,木头鸭子不会飞为什么要让它实现飞的功能。)
最后有人提问接口和抽象类的区别:
接口可以多继承,抽象类只能但继承。接口定义组件间的合同。使用抽象类为一个is a的关系。
posted on 2006-03-29 17:00KiddLee 阅读(1979)评论(12)  编辑 收藏引用网摘 所属分类:设计模式

FeedBack:
# 建议作者使用摘要方式发布, 请参考:http://www.cnblogs.com/dudu/articles/52480.aspx 第四项。  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-03-29 17:07 Terrylee
呵呵,总结得不错
有一个笔误:应该是“开放封闭原则”,不是“开发封闭原则”  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-03-29 17:55
这个讲师对抽象类理解的不到位。
其实在实际编程中抽象类的应用不比接口少。原因在于它既可以定义供继承的方法(避免重复),又可以象接口一样规定必须实现的方法。ms也是对抽象类推崇备至的。  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-03-29 23:13 Dflying Chen
接口实现契约,是不变的。继承实现扩展与重用,是可变的。  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-04-22 14:50 ivan
其实上面那个例子举得不是很好,抽象类应该是可实现抽象方法或都不实现抽象方法的,如果有的鸭子要飞那么就调用抽象类中的fly的方法.这样都不用去修改其它子类呀,为什么要说成要修改其它子类的呢~!  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-04-22 16:08 kid_li
@ivan
抽象类中的抽象方法如果不被继承的子类实现,那么子类还是一个抽象类,也就无法实例化,从模型的角度看,如果某个属性或方法与这个模型的本身没有关系,那么这个模型为什么要拥有这个属性或方法呢?例如:木鸭子不会飞,就不应该它实现fly的方法。  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-04-22 16:19 kid_li
@ivan
上面说的例子是游戏的设计者在第一版游戏中没有用到鸭子飞行的方法,但是在第二版游戏中需要添加这个功能,如果在抽象类中加入fly的话,所有的子类都要对这个方法就行实现(不会飞的鸭子类不应该要变动),这是因为继承的依赖性。如果我们改成“has a”的关系,那么问题就简单多了  回复  更多评论

# 请教几个问题 2006-05-16 16:25 ssgrl
有几个设计模式方面的问题想请教一下:
1、JAVA语言不支持泛型技术,那么如何在JAVA中构造同构容器?请简述思路。
2、当我们设计一个应用程序的用户界面时,某些情况下可以使用合成模式,请举一例。
3、在足球赛中,参与者有球队,球员,教练,比赛,裁判等。一个球队由11名球员和一个教练组成(为简化,我们不考虑替补),每场比赛有两个队,一位裁判(为简化,我们仅考虑主裁判),整个比赛有N场比赛(为简化,我们不考虑小组赛,淘汰赛等细节区别),请对这个案例建立对象模型(描述建立哪些类或对象,彼此的关系)。请使用文字描述,并画出UML图。
4、为保护公众安全,英国决定部署交通系统联合防护网:如果任何地方发生了某类可疑事件,这个消息将会被立即发送给网络内所有机构,注意:网络内的机构是动态变化的,可以加入或者退出,可疑事件的类型也是可能动态扩展的。请使用面向对象的设计模式,简述此类需求的解决方案。
回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-05-17 11:09 kid_li
@ssgrl
1、听了一些C#2.0的东西,其中提到了Java中的范型实现,据说在Java1.5中已实现,但并不是在虚拟机层面上,而是编译器层上的,也只是用java.lang中的object类型进行类似装箱拆箱,也就是对类型的转换。但是这种方式有一定的危险性,而且性能不是很理想。危险性在于,在将object类型转换成其他类型的时候,你必须确定object对象能够转换,性能不高是因为,这种转换毕竟不如范型的类型参数效率高。
当然,对于Java,我了解得不多,以后我会加强这方面的学习。
2、对于合成模式,大概看了一下,给我很重要的感觉是它可以将“一对多”的关系转化为“一对一”的关系解决。我觉得,类似树形的实现可以采用这种模式。我是刚开始学习设计模式,设计模式的Blog也在继续写,今后写到合成模式时,我想我会有更深的理解,到时候,我会再好好想想你的问题。
对于你省下的问题,比较具体,现在工作有点忙。如果不急,近期我会发Email给你我的想法  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-06-04 21:57 main
最近一直在听下载的视频资料,多交流,一起分享!  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-07-18 13:59
作者提到:"突然,我们发现有的鸭子会飞,我们会在Duck中在加上一个抽象方法abstract void fly();于是我们不得不在所有的子类当中添加fly的实现" ,这里我有点不解,既然是某些鸭子会飞,如果加了抽象方法那不是所有的实现子类都要实现飞的方法?
作者还提到“如果我们把这些方法都提取出来,把它变成Duck的成员” 那不所有的鸭子子类都有飞的属性?
我觉得在这里可以单独设计一个接口,会飞的鸭子就实现这个接口不就行了  回复  更多评论

# re: 设计模式学习笔记(一)——面向对象设计模式与原则 2006-07-18 14:36 kid_li
@大雁
例子是为了说明在抽象类中加入抽象方法或方法,以造成了对于子模块中出现的一些问题,也就是继承增加了父子模块的偶合度。设计模式中希望用组合的方式代替继承方式,以减小模块间的偶合。
对于第一个问题,哈哈,子类继承父类后,要实现父类中的所有抽象方法,否则此子类还是一个抽象类。
对于第二个问题,你说的有道理,设计模式中提倡面向接口编程  回复  更多评论
设计模式学习笔记(一)——面向对象设计模式与原则 设计模式学习笔记(一)——面向对象设计模式与原则 设计模式学习笔记(一)——面向对象设计模式与原则 《Java与模式》学习笔记:设计模式——原则 - shanchao的专栏 - CSDNBl... 《Java与模式》学习笔记:设计模式——树结构(合成模式 模板模式) 《Java与模式》学习笔记:设计模式——抽象工厂模式 - shanchao的专栏 - CS... 《Java与模式》学习笔记:设计模式——模板(Template)模式 面向对象设计原则 面向对象的设计原则-类设计原则 ——希赛网软件工程频道面向对象 设计模式学习笔记(七)——Adapter适配器模式 设计模式学习笔记(八)——Bridge桥接模式 设计模式学习笔记(十四)——创建型模式总结 设计模式学习笔记(十五)——结构型模式总结 设计模式学习笔记(十六)——Template Method模板方法模式 《设计模式精解》学习笔记 《设计模式精解》学习笔记 设计模式的原则 GOF设计模式学习笔记(二)---Prototype模式 - realsmy - BlogJava 面向对象的设计原则-类设计原则 [原创]敏捷设计之面向对象设计原则 (入选推荐日志,加20币) - 航行日志——理论与实践... 61条面向对象设计的经验原则61条面向对象设计的经验原则 面向对象设计准则 设计模式 [JAVA技术]61条面向对象设计的经验原则