第一篇:最简单的设计模式学习
最简单的设计模式学习:Singleton模式
学习设计模式,自然从最简单的模式入手,而最简单的模式便是Singleton。所以第一篇就来所以说Singleton模式。看完GOF和Design patterns in Java的书,感觉Singleton虽然简单,但是想写出一个好的Singleton也不是一上来就能写出来的。
Singleton模式的用处自然是保证一个类只有一个唯一的实例。在建模中涉及到的只能有一个对象,例如Struts中的Action类就是一例。除此之外,Singleton还使得该对象只有一个全局访问点。这就是SIngleton的作用。
说得比较抽象,我们来看一个简单Singleton的C++和Java的代码:
C++ Singleton模式:
类定义:
1.class Singleton
2.{
3.public:
4.static Singleton * Instance();
5.~Singleton();
6.7.private:
8.Singleton();
9.10.static Singleton * instance;
11.};
方法实现:
1.Singleton * Singleton::instance = 0;
2.3.Singleton::Singleton()
4.{
5.6.}
7.8.Singleton::~Singleton()
9.{
10.11.}
12.13.Singleton * Singleton::Instance()
14.{
15.if(instance == 0){
16.instance = new Singleton();
17.}
18.19.return instance;
20.}
Java Singleton模式:
1.public class Singleton {
2.3.private static Singleton instance;
4.5.public static Singleton getInstance(){
6.if(instance == null)
7.instance = new Singleton();
8.9.return instance;
10.}
11.12./** *//** Creates a new instance of Singleton */
13.private Singleton(){
14.}
15.}
通过上面的例子可以看出,Singleton的实现并不难,只要将构造函数访问域设为私有,然后添加一个静态引用和一个获得该应用的静态方法即可。其实在C++中定义一个全局静态变量也可以达到这个效果,但是像Java这样的语言就是能使用Singleton了。
上面的程序有一个问题,就是只能运行在单线程的环境下。为此我在C++上作了个实验。首先#include。在SIngleton::Instance()函数中增加一个Sleep(1000),程序如下:
1.2.3.4.5.6.7.8.9.Singleton * Singleton::Instance(){if(instance == 0){Sleep(1000);instance = new Singleton();}return instance;}
然后在主函数中创建两个线程,程序如下:
1.static Singleton * s1 = 0, * s2 = 0;
2.3.DWORD WINAPI ThreadProc1(PVOID)
4.{
5.s1 = Singleton::Instance();
6.7.return 0;
8.}
9.10.DWORD WINAPI ThreadProc2(PVOID)
11.{
12.s2 = Singleton::Instance();
13.14.return 0;
15.}
16.17.int main(int argc, char* argv[])
18.{
19.DWORD threadID1;
20.DWORD threadID2;
21.22.CreateThread(NULL, 0, ThreadProc1, NULL, 0, &threadID1);
23.CreateThread(NULL, 0, ThreadProc2, NULL, 0, &threadID2);
24.25.Sleep(10000);
26.27.std::cout << s1 << “ ” << s2;
28.29.return 0;
30.}
这样修改后在运行程序,打印出来的s1和s2地址就不是同一个地址了。结果如下: 0372D68 00372E68Press any key to continue
可见当在多线程环境下使用这个Singleton就会出现创建不止一个实力的情况,所以我们需要给Singleton加锁。请看下面的代码。
C++ Singleton模式:
1.2.3.4.5.6.7.class Singleton{public:static Singleton * Instance();virtual ~Singleton();private:
8.Singleton();
9.10.static CMutex mutex;
11.static Singleton * instance;
12.};
1.Singleton * Singleton::instance = 0;
2.CMutex Singleton::mutex;
3.4.Singleton::Singleton()
5.{
6.7.}
8.9.Singleton::~Singleton()
10.{
11.12.}
13.14.Singleton * Singleton::Instance()
15.{
16.mutex.Lock();
17.18.if(instance == 0){
19.Sleep(1000);
20.instance = new Singleton();
21.}
22.23.mutex.Unlock();
24.25.return instance;
26.}
此外需要#include < afxmt.h>,并且在项目设置中要设置动态链接MFC库。Java Singleton模式:
1.2.3.4.5.6.7.8.public class Singleton {private static Singleton instance;private static Object lock = Singleton.class;public static Singleton getInstance(){synchronized(lock){if(instance == null)
9.instance = new Singleton();
10.11.return instance;
12.}
13.}
14.15./** *//** Creates a new instance of Singleton */
16.private Singleton(){
17.}
18.}
运用加锁就可以解决在多线程环境下使用Singleton模式所带来的问题了。原文出处:中软卓越http://http://
第二篇:哪些设计模式最值得学习
回想起来,这几年在园子里发布的有关设计模式的随笔都有一个共同的特点。那就是
Factory和Singleton居多,如果是系列的,也往往是从这两个模式开始的。由于能够坚持把《设计模式》中所有模式都写完的非常少,所以基本上也很少见到有关其它模式的随笔。这种情况也很好理解,因为《设计模式》这本书就是按照这个顺序来的。最先讲述的就是Abstract Factory模式,于是它排第一也无可厚非;排第二的Builder基本不太容易见到;第三的Factory Method由于也叫“Factory”所以往往和Abstract Factory放在一起,或者干脆就混淆了; 第四的Prototype也不是太容易见到;第五位的Singleton简单易懂,易学易用。而再往后的模式,恐怕作者们就没什么耐心学下去了……这可能就是为什么Factory和Singleton出现频率如此之多的原因吧。
《设计模式》已经出版超过15年了,到今天已经不是什么新鲜的东西了,可以说正在由“绝招”慢慢向着“基本功”转变着。然而,这种学习模式的方式方法却实在令人担忧。Abstract Factory在实际中并不常见,因为它需要你有两套并行的继承体系,需要对同一个抽象有多于一种的实现方式。这种复杂的系统可以说不是每个领域,每个开发人员都能遇到的。在某些特定的领域可能很常见,但是在大多数领域并不需要这么复杂的对象创建方法。这就造成了很多人“杀鸡用宰牛刀”,用复杂的方式,解决不那么复杂的问题。后果是增加了不必要的复杂度,给系统维护增加了困难。
另一个模式Singleton,由于实现简单,意图“似乎”也很明显。被很多人用来作为“优化”的一种方式。通过这种方式来节省内存空间,减少对象实例。但是单一实例本身就等同于全局变量,而全局变量在几十年前就已经被证明是“反模式”了,用另一种形态的全局变量来代替另一种形态的全局变量有什么好处么?问题在与,Singleton的“意图”并不在于优化,而是在于“妥协”。Singleton的目的在于保证对象有单一的实例,这是因为对象必须要有单一的实例,如果存在多个实例,可能会引发错误。也就是说,Singleton以牺牲程序的清晰
和可维护性,来达到保证程序正确的目的。这跟本就和优化八竿子打不着,这完全是一种设计上的妥协,牺牲一些好处来获取更大的好处。如果仅仅是为了节省几个对象实例,而非程序的正确才使用Singleton,那就是丢了西瓜拣芝麻。况且节省那几个实例也跟本就不可能对程序的性能有太大的影响(特殊领域除外)。
人的时间是有限的,23个模式也不是都那么常用,哪些模式才是最经常用到的,才是最值得学习的呢?
第一梯队:Iterator,Observer,Template Method,Strategy
Iterator:LINQ,foreach这不都是Iterator么。
Observer:MVC的核心,.NET中事件就是Observer。
Strategy:对同一个行为有不同实现的时候,如果考虑将行为的实现委托(不是.NET中的委托)给另一个类,那就用到了Strategy。通过这种方式,可以简单的替换算法的实现类,来达到更换算法的目的。
class Foo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
public void DoSomething()
{
//some code
bar.DoWhatYouWant();
//some code
}
}
class A : IBar
{
public void DoWhatYouWant()
{
//do in A's way
}
}
class B : IBar
{
public void DoWhatYouWant()
{
//do in B's way
}
}
Template Method:一个算法的同一个步骤有不同的实现,通过继承来实现。这种方式通过创建子类来改变算法的实现和行为。ASP.NET WebForm中Page的OnInit,OnLoad等事件,就是Template Method。
class Foo
{
public void DoSomething()
{
//some code
DoWhatYouWant();
//some code
}
protected abstract void DoWhatYouWant();
}
class A: Foo
{
protected override void DoWhatYouWant();
{
//do in A's way
}
}
class B: Foo
{
protected override void DoWhatYouWant();
{
//do in B's way
}
}
面向对象的一个重要特点就是多态,也就是对于同一个动作有不同的行为。Strategry通过委托的方式,将一个算法的不同实现委托给其它类;Template Method通过继承的方式,让子类实现算法的可变部分,基类则处理算法的流程和不变部分。近年来组合优于继承的观点已经成为主流,因此Strategy的处境频率相对高一些,但是Template Method在解决简单问题的时候更好用,只要注意继承层次不要太多(<=3)就好。
第二梯队:Adapter,Facade,Decorator
Adapter:当你需要使用第三方库,但是又不想太依赖于它的API,以便于今后在需要时可以方便的切换到另一个库的时候,你就需要在你的代码和第三方API之间放置一个抽象层,也就需要用Adapter模式了。比如你想使用log4net,如果直接在代码中到处引用log4net的API,将来有一天需要切换到另一个库比如EntLib,你的改动量可就大了去了。如果在一开始就自己设计一个API,在代码中使用自己的API,再用Adapter模式将log4net的API包装到自己的API中,如果有一天想要切换到Entlib,只要为EntLib在写一个Adapter就行了。对于IoC框架也是一样的。不过需要注意的是,如果第三方库的API接口非常庞大,使用Adapter就会很麻烦,因为你需要包装太多的东西,那么使用Adapter可能就不是一个太好的主意。或许谨慎考虑确定一个不太可能会变化的第三方库更好一些。
Facade:基本上用于简化API,隐藏细节,在一个系统中,高层模块调用低层模块时,如果低层模块API比较复杂,而高层模块并不需要这种复杂度,那么加一个Facade,可以简化高层模块使用API的难度。
Decorator:为一个类的行为增加行为,比如ASP.NET MVC中的Action Filter。第三梯队:Command,State,Composite
Command:统一接口,Undo/Redo。
State:当你的model有多种状态,model的行为在每种状态下并不一样的时候,就需要用State。如果你有多个相似的Switch,那也可能意味着需要用State来代替Switch。
Composite:ASP.NET WebForm的Page和Control就是一个例子。
这些模式和分类只是凭我的感觉,并没有任何实际的数据做支持,而我的感觉也只来源于我所接触到的领域和代码。希望同学们也可以提供自己接触到的代码中,最常见到和用到的模式。
第三篇:学习设计模式的一些感想
设计模式在编程中的应用
我们在发现问题到解决问题这个过程中,常会发现很多问题是重复出现的,或是某个问题的变体,外在不同,而本质相同,建筑学上如是,软件行业也是,这些问题的本质就是模式。有人说,设计模式并不是一日两日能够理解的,当编程经验到了一定程度,便迫切的需要设计模式来完善自己的代码、优雅自己的设计,以及减少重复编码,这句话也是蛮有道理的,以自己的亲身经历来说,当刚开始编程时,没有一点设计理念,等到开设这门课以后再细读理解,把里面的思想带到自己的项目中,就会觉得有很多值得深思的地方。本文以我在以往项目中遇到的三个编码问题来谈谈学习设计模式的必要性。
一、代码量激增、程序可维护性面临挑战
我想这样的代码我们从学习C语言就开始接触,现在很多地方还在用,以后工作可能用的更多但是,大家都写的东西,我们自己的优势在哪里呢?
1.过多的if„else判断 if(type == 1){ //调用获取信息方法1 } else if(type == 2){ //调用获取信息方法2 „„.} else { //调用获取信息方法7 } 这是我在做一个项目中看到的一段代码,那个条件判断非常之长,有7个条件分支,而且其他有些地方也有根据类型来做不同处理的情况。
2.多次载入资源(例如配置文件的读取),引起资源损耗
public static String getProperty(String propKey)throws Exception...{ Properties prop = new Properties();InputStream propConfFile = Util.class.getClassLoader().getResourceAsStream(“configure.properties”);//载入propConfFile到prop中,从prop中获取propKey的值,并将其返回 }
该段代码是我以前在一个项目中写的一段代码,该段代码用于读取配置文件的属性,但该段代码是存在一些问题的,因为在每次获取属性时,它都重新载入资源,造成了资源的过多损耗。
3.过多依赖实现类
1)水果接口类—Fruit.java public interface Fruit { public void grow();}
2)水果的实现类—Apple.java、Strawberry.java //略
3)测试类—Test.java public class Test { public static void main(String[] args){ Fruit apple = new Apple();Fruit strawberry = new Strawberry();} } 在我们的项目中尚未采用Spring时,类似这样的程序很多,与实现类的过度耦合是这段代码存在的一个主要问题。
在我编码的过程中,遇到的问题还有很多。不够优雅的代码、过于僵硬的设计,等等,通过改进如上编码来认识学习设计模式给我们的编码带来的好处。
二、借“设计模式”之力冲出代码包围圈
如上的三段代码,都是存在不少问题的,让我们一一讨论,通过在其中应用设计模式,来优化我们的这三段代码,提高其扩展性和易维护性。
1.解决过多的if„else判断问题
如果在一段代码中,不少地方需根据某类型或状态等做出不同的处理,那当类型或状态增加时,这些代码将会过于僵硬,扩展性差,只有在各个分布了if„else的再增加一个else if,可维护性可想而知。设计模式中有一种模式可以解决该问题,即状态模式。状态模式给我们带来的好处如下:
1)状态模式需要对每一个对每一个系统可能取得的状态创立一个状态类(State)的子类,当系统的状态变化时,系统改变所选的子类。与一个特定的状态有关的行为都被包装在一个特定的对象里,而且当需要增加新的状态时,可以以子类的方式将它加到系统里,从而提高了易维护性和可扩展性;
2)由于每一个状态都被包装到了类里面,避免了使用过多的条件转移语句。
下面我们对该例进行演示性的改进。我们可以定义一个类型接口,该类相当于状态模式中的状态类。
public interface Type { /** * 获取信息 */ public Object getInfo();/** * 获取结果 */ public Object getResult();} 类型
1、类型2等可以实现该接口,代码略:
2.解决过度资源损耗问题
在该例中,每次通过getProperty(„)方法获取某属性时,都会重新载入文件中的所有内容,造成资源的不必要损耗。该设计模式中,对于此种情况,可以通过单例(Singleton)模式来优化处理。import //略
public class PropertiesUtil...{ private static Map propertiesMap = null;public static String getProperty(String propKey)throws Exception...{ if(propertiesMap == null)...{ //当propertiesMap为空时,载入文件,将其键值对放入propertiesMap中(略)} //在propertiesMap中获得propKey属性,并将值返回(略)} }
可以考虑实现单例模式的地方还有很多,例如:
1)对于计算机的外部资源打印机的情况,因只有一个Printer Spooler,为避免两个打印作业同时输出到打印机中,可考虑用单例模式实现。
2)Window的回收站在整个系统中只有唯一的一个实例,而且回收站自行提供自己的实例,回收站也是单例模式的应用
3、解决过多依赖实现类问题
在该例的测试类Test.java中,通过Fruit apple = new Apple();来获得对象,造成了程序过多的依赖实现类,与实现类过度耦合,学习设计模式后,我们可以考虑采用工厂模式来实现,可对代码进行如下改进:增加工厂类FruitGardener.java,该类的工厂方法如下: public static Fruit factory(String fruitType)...{ if(fruitType.equalsIgnoreCase(“apple”))...{ return new Apple();} else if(fruitType.equalsIgnoreCase(“strawberry”))...{ return new Strawberry();} else...{ return null;} }
增加了水果工厂类后,测试类也要做对应修改,修改后的Test.java的main方法如下: Fruit apple = FruitGardener.factory(“apple”);Fruit strawberry = FruitGardener.factory(“strawberry”);
在进行了对应修改后,测试类大大减少了对水果实现类的依赖,由直接new实现类变成了通过传入字符串来获得需要的实例,工厂模式应用很广泛,例如在现在红得似火的spring也在不少地方用了工厂模式,它本身就是一个很大的bean工厂,不过它在代码上进行了更大的改进,各实现类可以通过配置文件设置。
三、设计模式 –––– 由优秀迈向卓越的阶梯
从以上三个例子中我们可以看出,通过使用设计模式,优化了我们的代码。这样的例子在我们日常的编码过程中有很多,在我们刚开始学习编码时,写这样的代码还说得过去,但随着经验的增长,我们需要更进一步,现有的设计模式给我们提供了解决大多数问题的好方案,当然,在实践的过程中,我们甚至可以探索出新的设计模式,来解决遇到的某类问题。
学习设计模式不是一蹴而就的,很多人叹息设计模式似乎很不错,然而在自己的编码设计生涯中用得极少,我想主要原因是因为对设计模式的学习还不够,还没将其变成属于自己脑袋里的东西,所以当问题变着面孔出现时,认识不到问题的存在,因为不能正确的分析问题、认识问题,当然也不可能很好的解决问题。
还未学习过设计模式或对其知之甚少的程序员们,努力学习设计模式吧,那将使你由一个优秀的程序员(Coder)成为一个卓越的软件设计师(Developer)。
第四篇:JAVA学习书籍- 设计模式
谈到设计模式很多人多会推荐GOF 的那本,该书在Amzon上是五星级的推荐书籍。不过对于学习java 没多久的、特别是java 初学者,我很不推荐这本书。主要是该书的例子基本都是C++的,很多细节没有讲述得足够清楚。
我给大家推荐的第一本是阎宏博士的《Java 与模式》,它是第一本中国人自己写的关于设计模式的书籍,写的比较有趣,融合了很多中
华民族的文化和观念,例子、类图都比较多,且相对简单!非常不错的入门书籍――又是大块头哦!
其次我推荐Wiley 出版社出版的《Pattern In Java》一套三本,我才看了第一本,好像第二本不怎么样,第三本还不错!
第三本是中文翻译版的关于多线程模式的(很难得的中文翻译版)中国铁道出版社2003 年出版的《Java 多线程设计模式》,将多线程模
式讲得非常浅显,配有大量的图例,每章都有习题,最后有答案!我研究多线程模式就是由它开始的!
第四本,今年出版的Head First 系列的《Head First Design Pattern》,秉承Head First 系列图书的优点,大量的类图、丰富的实例、有趣的注解,值得购买!
其次在J2EE 方向你可以研究阅读Addison Wesley 2002 年出版的《Patterns of Enterprise Application Architecture》,众多大腕的作品,讲企业消息集成的!Sun 提供的《J2EE PATTERNS SL500》也很好!晚了推荐那一本Amzon 4 星半的《Holub on patterns》,大师的作品,提供了,很值得研究的例子,不过对上面四本不是很熟悉的读者,最好不要读它!可能会让你比较累!
我学习设计模式经过一段很曲折的路线,前前后后大约看了20 本,阎宏博士的《Java 与模式》我看了4 遍,还排除我第一次基本没看
懂的看!记得研一时老师给我们讲了GOF 的那本,作为选修课,我和它们计算机系的硕士、博士们一起,到最后一个班40-50 个人,不
超过3 个人明白,我也没有明白任何一点(基础差吧――主要我对C++语言一点都不了解),凭我不伏输的性格,我认为我对java 语言理
解还可以,我就借了《Java 与模式》,结果还是基本没看懂。很有幸的是读研三时,听过了上交大饶若楠老师关于Java OOP 语言的讲座,我懂了组合书籍模式等三种设计模式后,对其它模式有了强烈的兴趣和要征服它的愿望!工作后我买的第一本就是《Java 与模式》,第一遍花了2 个月研究了这个1000 多页的大块头,后来第三遍15 天左右就可以搞定,笔记记了一大本!从此一发不可收拾。
选对书、埋头研究。相信很快就会入门的!
学习Java 语言8 个简单的部分,这只是我们研究Java 语言的开始!这些都懂了充其量一个java 程序员而已,后面的路很长很长!我们
可以继续研究数据库实现的源代码、Servlet 服务器的源代码、RMI、EJB、JNDI、面向方面编程、重构、ANT 工具、Eclipse 工具、Spring
工具、JBoss、JOnAS、Apache Geronimo 等J2EE 服务器!研究了这些你可能会成为一个出色的J2EE Architecture!你可以继续研究剖
析器、编译器、JNODE(java 写的操作系统)
第五篇:简述为什么要学习设计模式
一、简述为什么要学习设计模式?
答题要点:复用解决方案:通过复用已经建立的设计,我为自己的问题找到了更高的起点并避免了绕弯路。我受益于学习别人的经验。我不必再为普通、重复的问题重新设计解决方案; 建立通用的术语:交流与协作都需要一个共同的词汇基础、一个对问题的共同观点。设计模式在项目的分析和设计阶段提供了一个通用的参考点;更高的分析和设计的视角:在问题上、在设计和面向对象的过程中,模式给你一个更高层次的视角。这样的视角将你从“ 过早处理细节” 的暴政中解放出来。
二、选取你所熟悉的三个设计模式,详细谈谈它们的意图、设计动机和适用性 答题要点:Singleton:定义一个Instance操作,允许客户访问它的唯一实例。Instance是一个类操作。负责创建它自己的唯一实例。
Adapter:属于结构模式,动机:为复用而设计的类不能够被复用的原因仅仅是因为接口与专业应用领域所需要的接口不匹配,适用性:你想使用一个已经存在的类,而它的接口不符合你的要求。
Template Method:意图:定义一个操作中的算法骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。动机:模板方法使用抽象操作定义算法的先后顺序,而子类将重新定义这些操作以提供具体的行为。适用性:一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复控制子类扩展
三、什么是IoC(Inversion of Control)、DIP(Dependency Inversion Principle)、Dependency Injection模式 ?举例说明?
答题要点:控制反转(Ioc)模式(又称DI:Dependency Injection)就是Inversion of Control,控制反转。在Java开发中,IoC意味着将你设计好的类交给系统去控制,而不是在你的类内部控制。这称为控制反转。
IoC(Inversion of Control)是近年来兴起的一种思想,不仅仅是编程思想。主要是协调各组件间相互的依赖关系,同时大大提高了组件的可移植性,组件的重用机会也变得更多。在传统的实现中,由程序内部代码来控制程序之间的关系。我们经常使用new关键字来实现两组键间关系的组合,这种实现的方式会造成组件之间耦合(一个好的设计,不但要实现代码重用,还要将组件间关系解耦)。IoC很好的解决了该问题,它将实现组件间关系从程序内部提到外部容器来管理。也就是说由容器在运行期将组件间的某种依赖关系动态的注入组件中。控制程序间关系的实现交给了外部的容器来完成。即常说的好莱坞原则“Don't call us, we'll call you”。
Ioc也有称为DI(Dependecy Injection 依赖注射),由Martin Fowler的一篇《Inversion of Control Containers and the Dependency Injection pattern》提出。DIP简介(DIP--Dependency Inversion Principle):高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
四、什么是Command?
答题要点:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或者记录请求日志以及支持可取消的操作。
五、说出你所知道的集中创建型模式。
答题要点:Factory Method,Abstract Factory,Builder,Prototype,Singleton