设计模式
什么是设计模式?每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题解决方案的核心。为什么要用设计模式?设计模式是某一类问题的解决方案,这样就可以一次次使用该方案而不必做重复劳动。可复用是设计模式的目标。
1. 引言
我们说的设计模式通常指的是面向对象的设计模式;在一些架构中还存在一些架构设计模式;数据库中存在一些数据库的设计模式。
1.1. 从面向对象谈起
面向对象蕴含着两个思维模型,底层思维和抽象思维。底层思维关心如何把握机器底层,进而从微观理解对象构造;抽象思维考虑向上,如何把我们的周围世界抽象为程序代码。
向下需要深入理解三大面向对象机制:封装、继承、多态。封装是为了隐藏内部实现;继承是为了复用现有代码;多态是为了改写对象行为。
向上需要深刻把握面向对象机制所带来的抽象意义,理解如何使用这些机制来表达现实世界,掌握什么是“好的面向对象设计模式”。
软件设计的金科玉律:复用!
1.2. 为什么要用面向对象?
变化是复用的天敌!面向对象设计最大的优势在于:抵御变化。
从抵御变化的角度,重新认识面向对象的概念:从宏观层面来讲,面向对象的方式更强调各个类的“责任”。从微观层面来讲,面向对象的方式更强调各个类的“责任”。
对象是什么?从语言层面来讲,对象封装了代码和数据;从规格层面来讲,对象是一系列可被使用的公共接口;从概念层面来讲,对象是某种拥有责任的抽象。
1.3. 八大设计原则
设计原则其实比某种具体的设计模式更重要,基于这些设计原则才能设计出属于自己的设计模式。依赖倒置原则、开放封闭原则、单一职责原则、Liskov替换原则、接口隔离原则、优先使用对象组合,而不是类继承、封装变化点、针对接口编程,而不是针对实现编程。
2. GOF-23模式分类
从目的来看,设计模式可以分为创建型模式、结构型模式、行为型模式三类。
创建型模式:将对象的部分创建工作延迟到子类或其他对象,从而应对需求变化为对象创建时具体类型实现引起的冲击。结构型模式:通过类继承或者对象组合获取更灵活的结构,从而应对需求变化为对象的结构带来的冲击。行为型模式:通过类继承或者对象组合来划分类与对象间的职责,从而应对需求变化为多个交互的对象带来的冲击。
设计模式的应用不应该先入为主,一上来就使用设计模式是对设计模式最大的误用,没有一步到位的设计模式。敏捷软件开发实践提倡的"Refactoring to Patterns"是目前普遍公认的最好的使用设计模式的方法。
2.1. 单例模式
在软件系统中,经常有这样一些特殊的类,必须保证他们在系统中只存在一个实例,才能确保逻辑正确性和良好的效率。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。
单例实现有两个途径:
- 将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;
- 在该类内提供一个静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。
- 恶汉式实现
类加载的方式是按需加载,且加载一次,代码中的单例类被加载时,就会实例化一个对象交给自己的引用。
// 饿汉式单例
public class Singleton1 {
// 指向自己实例的私有静态引用,主动创建
private static Singleton1 singleton1 = new Singleton1();
// 私有的构造方法
private Singleton1(){}
// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton1 getSingleton1(){
return singleton1;
}
}
- 懒汉式加载
懒汉式加载起到了Lazy Loading的效果,但是由于if(singleton == null)
语句,会导致懒汉式加载只能在单线程情况下使用。
// 懒汉式单例
public class Singleton2 {
// 指向自己实例的私有静态引用
private static Singleton2 singleton2;
// 私有的构造方法
private Singleton2(){}
// 以自己实例为返回值的静态的公有方法,静态工厂方法
public static Singleton2 getSingleton2(){
// 被动创建,在真正需要使用时才去创建
if (singleton2 == null) {
singleton2 = new Singleton2();
}
return singleton2;
}
}
- 双重加锁机制
public class Singleton
{
private static Singleton instance;
//程序运行时创建一个静态只读的进程辅助对象
private static readonly object syncRoot = new object();
private Singleton() { }
public static Singleton GetInstance()
{
//先判断是否存在,不存在再加锁处理
if (instance == null)
{
//在同一个时刻加了锁的那部分程序只有一个线程可以进入
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
- 静态初始化
//阻止发生派生,而派生可能会增加实例
public sealed class Singleton
{
//在第一次引用类的任何成员时创建实例,公共语言运行库负责处理变量初始化
private static readonly Singleton instance=new Singleton();
private Singleton() { }
public static Singleton GetInstance()
{
return instance;
}
}
参考文献
[1] https://www.cnblogs.com/xuwendong/p/9633985.html