我们在设计程序时经常会遇到⼀些设计上的问题,也就是怎样把⼀个复杂的问题简单化和模式化。因为如果我们使⽤⾮常复杂的算法来解决,最终⾯对的问
题必然是其他合作⼈很难看懂,更有甚者,过⼀段⼉时间以后⾃⼰也看不懂了。有没有很好的⽅式来解决这些问题呢?当然最直接的⽅式是提升⾃⼰的设计能
⼒,其实我们还可以学习其他⼈的设计思想。
我们的软件先驱们已经遇到过很多重复性的设计问题,他们把这些问题的解决⽅法进⾏了归纳总结,其中最著名的就是”四⼈帮”(GOF)提供的 23 种经典
设计模式,这些模式中⼜分为 3 类:创建型模式(Creational Pattern)、结构型模式(Structural Pattern)和⾏为型模式(Behavioral Pattern),我们会在以后的期刊
中连载为⼤家介绍这些模式。
接着就是模式问题,为什么要使⽤模式?这有⼏个好处,⾸先这些模式都是经过实践检验的,程序员⼴泛使⽤在各种程序中,充分证明了这些设计是⾮常好的设计⽅式。第⼆个重要的优势就是这些模式被⼴泛使⽤,你使⽤了某种模式设计了程序⼀部分,另⼀个懂设计模式的⼈⼀眼就能看出你设计的意图,奠定了程序员之间沟通的基础。
学习设计模式和学习语⾔语法类似,⾸先我们要知道为什么会出现这种模式,这种模式是解决哪类问题的,它适⽤于那些场景,我们应该怎样灵活的适⽤
和扩展它。当然对我们同学来说,我们可能遇到的实际问题情况还⽐较少,也很难能真正完全应⽤上所有这些模式,但学习设计模式是提升⾃⼰设计能⼒的⼀种⽅式,通过学习前辈们成熟的经验来扩展我们的视野。设计能⼒是程序员的内功,也是⾛向成功的必经之路。
本系列⽂章是⾯对我们系的各位同学,所以代码和场景都会尽量精简,以掌握每个模式的基本意义为⽬的,所以没有涉及到太多的延伸和扩展,当然我也会
对扩展进⾏⼀些提⽰,等同学们的设计能⼒达到⼀定⾼度的时候,可以再去深⼊的研究模式的延伸部分。
我们先从创建型模式开始⼊⼿,在以前学习的语法中,⼤家可以通过 new关键字在堆中创建对象,⽽且使⽤ new 的⽅式和次数是没有限制的,但是在我
们实际设计的过程中会产⽣⼀些需求,对对象的创建要采取⼀些控制⼿段来达到⽬的。⽐如我们考虑下⾯的⼀个场景:
当我们设计⼀个⾜球⽐赛的游戏时,在⾜球场上只应该出现⼀个⾜球对象,在开发⼩组中,我们负责构建⾜球类,其他⼈会调⽤我们的⾜球类代码⽣成⾜球
对象。这时我们该怎样处理?仅仅定义⼀个 public class Ball{ } 类吗?其他⼈可能 new 很多次 Ball(); , 这样⼀个⾜球场上就会出现很多 Ball 对象,显然是不符
合要求的。
这⾥的关键就是要控制调⽤⽅ new 我们的 Ball 类,怎样让别⼈不能 new 我们的类?我们考虑⼀下调⽤ new 的时候实际是调⽤那些代码呢?对,就是构造
函数,每次 new 都会调⽤构造函数,我们可以想办法让调⽤⽅不能执⾏构造函数,这样他们就不能 new 出新对象了。到这时很多同学应该都会想到访问修饰
符,public 公开的,private 私有的,办法就在这⾥。
public class Ball { private Ball() { } }
第⼀个问题解决了,但是毕竟我们还得想办法可以 new 出来⼀个⾜球对象,让调⽤⽅可以拿到⾜球,private 限制了只能在类内部访问,所以我们也只能在
类内部去 new, 怎么做呢?最直接的办法就是我们要在类内部公开出⼀个⽅法,new 出⼀个 Ball 对象,然后返回给调⽤⽅。当然这个⽅法不能是实例⽅法,因为调⽤⽅本⾝就不能直接new 出对象,也就更不可能调⽤对象的实例⽅法了,所以这个⽅法肯定只能是
静态⽅法。
public class Ball { private Ball() { } public static Ball GetBall() //调⽤⽅取得Ball对象 { return new Ball(); } }
当然这个⽅式还不⾏,每次调⽤ GetBall()都会产⽣⼀个新对象,我们必须要想办法控制只能产⽣唯⼀⼀个 Ball 对象。
这时我们会想到这个逻辑,如果还没有 Ball 对象,则 new 出⼀个 Ball,如果已经有了,我们就不能再 new 了,直接返回已经有的那个 Ball 对象就⾏了。
怎样判断是否已经有了⼀个 Ball 对象?我们可以⽤ Bool,那怎样保存已经有的那个对象呢?我们可以定义⼀个静态字段来保存这个对象。⾄此,整个逻辑已经
完整,我们看⼀下代码。
public class Ball { private Ball() { } private static Ball ball; //保存唯⼀的Ball对象 public static Ball GetBall() //调⽤⽅取得Ball对象 { //如果没有则new⼀个Ball,如果已经有了则不⽤再new了。 if (ball == null)- 20 - ball = new Ball(); return ball; } }
功能已经实现,满⾜⼤部分情况,但是并不完美,⽐如说多线程访问下还是可能产⽣多个实例,可以采⽤锁机制防⽌;再⽐如说某些情况下需要设计⼦类,
也需要考虑访问限制和重写机制;当然有些情况下还可能会有些扩展,产⽣固定⼏个类,或者产⽣⼀个对象池。这些都需要同学们以后深⼊去挖掘。
这就是创建型模式中最简单也是最常⽤的“单件(例)模式”,我们下期还会接着讨论更多的创建型模式,创建型模式就是控制对象的⽣成⽅式。最后希望朋
友们能学以致⽤,这样才能有更深⼊的理解。