23种设计模式介绍以及在Java中的实现

原创不易,转载请注明出处:http://blog.csdn.net/anxpp/article/details/51224293,谢谢!

文章比较长,读者可以通过顶端的目录选择要了解的模式,然后通过文章右边的按钮快速返回顶部重新选择一个新的模式浏览

博主精心准备了大量的示例代码。文章尽量提供与编程相关的例子,而不是像多数其他介绍的文章一样,提供一些感觉挺滑稽的例子(那样的例子可能看完觉得写得很好,然而还是不会用...)。

本文耗费了作者大量时间,还请亲们给个赞O(∩_∩)O~

也可以通过CTRL+F并输入要了解的模式并跳到对应位置。

文章中的示例源码在github上:https://github.com/anxpp/JavaDesignPattern

文中未给出UML图,如果需要请回复说明,本人也可以画出需要的设计模式对应的UML图。

设计模式介绍及Java描述

概述
设计模式是针对某一类问题的最优解决方案,是从许多优秀的软件系统中总结出的。

Java中设计模式(java design patterns)通常有23种。

模式可以分成3类:创建型、行为型和结构型。

创建型模式
创建型模式涉及对象的实例化,特点是不让用户代码依赖于对象的创建或排列方式,避免用户直接使用new创建对象。

创建型模式有以下5个:

工厂方法模式、抽象工厂方法模式、生成器模式、原型模式和单例模式。

行为型模式

行为型模式涉及怎样合理的设计对象之间的交互通信,以及怎样合理为对象分配职责,让设计富有弹性,易维护,易复用。

行为型模式有以下11个:

责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。

结构型模式
结构型模式涉及如何组合类和对象以形成更大的结构,和类有关的结构型模式涉及如何合理使用继承机制;和对象有关的结构型模式涉及如何合理的使用对象组合机制。

结构型模式有以下7个:

适配器模式、组合模式、代理模式、享元模式、外观模式、桥接模式和装饰模式。

模式中涉及的重要角色,会在描述中(加粗字体)介绍出来。下面就逐一介绍。

1、单例模式(Singleton Pattern)
Ensure a class only has one instance,and provide a global point of access to it.

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

何时使用

当系统需要某个类只有一个实例的时候
优点

单例模式的类唯一实例由其本身控制,可以很好的控制用户何时访问它。
单例模式概念很简单,而且也比较常用。

在使用这个模式的时候,我们要考虑是否会在多线程中使用,如果不会应用于多线程,那写法就足够简单:

public class SimpleSingleton {
private static SimpleSingleton instance;
private SimpleSingleton(){}
public static SimpleSingleton getIntance(){
if(instance == null)
instance = new SimpleSingleton();
return instance;
}
}
上例就是一个简单的单例模式实现,使用了懒加载模式。但是多线程中可能会创建多个实例。下面就介绍多线程中的使用。

如果直接将上面例子应用到多线程中,可以直接把getInstance()设置为同步的(synchronized),但是并不高效,任一之后,只能有一个线程可以调用这个方法,其余的会排队等待。

所以整个方法做同步不是优解,那就只同步代码块就好了。这就引出了双重检验锁,即在同步块外检查一次null,然后再在同步块内检查一次。但是最终这种方式也是会有问题的,使用静态内部类是一种比较好的方式。

单例模式使用很频繁,也很简单,但不一定都能写对,详细的写法请参考:如何正确地写出单例模式。里面详细的分析的单例模式的各种写法。

其他模式中的示例代码,有很多时候用到了单例模式,此处就不额外添加例子了。

这里给出一个推荐的实现方式(枚举):

public enum EasySingleton{
INSTANCE;
}
2、工厂方法模式(Factory Method Pattern)
别名:虚拟构造(Another Name:Virtual Constructor)。

Define an interface for creating an object,but let subclasses decide which class to instantiate.Factory Method lets a class defer instantiation to subclassess.

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

何时使用

用户需要一个类的子类的实例,但不希望与该类的子类形成耦合
用户需要一个类的子类的实例,但用户不知道该类有哪些子类可用
优点

使用工厂方法可以让用户的代码和某个特定类的子类的代码解耦
工厂方法使用户不必知道它所使用的对象是怎样被创建的,只需知道该对象有哪些方法即可。
简单工厂模式

介绍工厂方法模式前,先介绍一下简单工厂模式,简单工厂模式也是一种工厂方法模式。

简单工厂模式又称静态工厂方法模式。从命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。

如果一个一些对象(产品),已经确定了并不易改变和添加新的产品,那么久可以使用简单工厂模式。下面就是简单工厂的例子:

//演示简单工厂
public class SimpleFactory {
public static void main(String args[]) throws Exception{
Factory factory = new Factory();
factory.produce(“PRO5”).run();
factory.produce(“PRO6”).run();
}
}
//抽象产品
interface MeizuPhone{
void run();
}
//具体产品X2
class PRO5 implements MeizuPhone{
@Override
public void run() {
System.out.println(“我是一台PRO5”);
}
}
class PRO6 implements MeizuPhone{
@Override
public void run() {
System.out.println(“我是一台PRO6”);
}
}
//工厂
class Factory{
MeizuPhone produce(String product) throws Exception{
if(product.equals(“PRO5”))
return new PRO5();
else if(product.equals(“PRO6”))
return new PRO6();
throw new Exception(“No Such Class”);
}
}
很容易看出,简单工厂模式是不易维护的,如果需要添加新的产品,则整个系统都需要修改。如果我们需要添加诸如PRO7、PRO8等产品,直接在工程类中添加即可。但是如果这时候根部不知道还有什么产品,只有到子类实现时才知道,这时候就需要工厂方法模式。

而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以实现起来是比较麻烦的,那么工厂方法模式正式解决这个问题的,下面就介绍工厂方法模式。

工厂方法模式

工厂方法模式去掉了简单工厂模式中工厂方法的静态属性,使得它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。

针对上面的例子,如果使用工厂方法模式,即将工厂定义为一个接口,然后由具体的工厂来确定需要生成什么样的产品,为了与简单工厂比较,这里还是贴上代码:

//工厂方法模式
public class FactoryMethod {
public static void main(String args[]){
IFactory bigfactory;
bigfactory = new SmallFactory();
bigfactory.produce().run();
bigfactory = new BigFactory();
bigfactory.produce().run();
}
}
//抽象产品
interface MeizuPhone{
void run();
}
//具体产品*2
class PRO5 implements MeizuPhone{
@Override
public void run() {
System.out.println(“我是一台PRO5”);
}
}
class MX5 implements MeizuPhone{
@Override
public void run() {
System.out.println(“我是一台MX5”);
}
}
interface IFactory{//抽象的工厂
MeizuPhone produce();
}
//工厂*2
class BigFactory implements IFactory{
@Override
public MeizuPhone produce() {
return new PRO5();
}
}
class SmallFactory implements IFactory{
@Override
public MeizuPhone produce() {
return new MX5();
}
}
如果了解Java的集合框架,那么它就是一个很好的例子:

Java中的Collection接口的实现都能通过iterator()方法返回一个迭代器,而不同的实现的迭代器都在该实现中以内部类的方式对Iterator接口实现的,然后通过iterator()方法返回。那么,这个iterator()方法就是一种工厂方法。

可以看到,在这里抽象产品是Iterator接口,具体产品就是Collection接口的实现中对Iterator接口的实现,构造者是Collection接口,其提供的工厂方法就是Iterator iterator();,具体构造者就是Collection的实现。而工厂方法模式的结构,也就是由前面加粗的4部分组成。

如果对Java容器不熟悉,下面再提供一个例子(模仿Iterator,其实顺便也介绍了Iterator):

如果有多种数据结构要遍历,我们就需要一种用于遍历不同结构的工具,首先我们就需要为这个工具定义一个接口(抽象产品),用于描述如何来遍历:

//只是需要遍历一堆数据,那么只需要2个方法就可以了
public interface Iterator {
boolean hasNext(); //是否还有下一个元素
T next(); //得到下一个元素
}
然后就是我们要遍历的目标,而这些目标此处我们暂定为列表,这就是构造者:

//便于介绍,不做多的操作
public interface List {
Iterator iterator(); //返回一个遍历器
boolean add(T t); //添加元素到列表
}
对于List可能有多种实现方式,比如数组和链表,此处就简陋的介绍一下,而这些就是具体构造者,而里面有遍历器的具体实现(具体产品),此处以内部类的形式放到了List的实现(具体构造者)里面,也完全可以修改代码将遍历器的实现(具体产品)独立出来:

数组的实现:

package com.anxpp.designpattern.factorymethod;
//方便演示而实现的简陋的数组list
public class ArrayList implements List{
private int size; //存放的元素个数,会默认初始化为0
private Object[] defaultList; //使用数组存放元素
private static final int defaultLength = 10;//默认长度
public ArrayList(){ //默认构造函数
defaultList = new Object[defaultLength];
}
@Override
public Iterator iterator() {
return new MyIterator();
}
//添加元素
@Override
public boolean add(T t) {
if(size<=defaultLength){
defaultList[size++] = t;
return true;
}
return false;
}
//遍历器(具体产品)
private class MyIterator implements Iterator{
private int next;
@Override
public boolean hasNext() {
return next

猜你喜欢

转载自blog.csdn.net/liuxinyang666/article/details/79123524