在《设计模式》这本书里,GoF定义了23种设计模式,个人能力有限,在实际使用或者业余编码过程中,并没有完全接触完全。这里我罗列一下在java中几种常用的设计模式。

GoF将设计模式分为了三大类:

  • 创建型模式
  • 结构型模式
  • 行为型模式

    创建型模式

    创建型模式就是创建对象的模式,抽象了实例化的过程。它帮助一个系统独立于如何创建、组合和表示它的那些对象。关注的是对象的创建,创建型模式将创建对象的过程进行了抽象,也可以理解为将创建对象的过程进行了封装,作为客户程序仅仅需要去使用对象,而不再关心创建对象过程中的逻辑。 常用的创建型模式有以下几种:

  • 工厂模式

  • 单例模式

  • 建造者模式

工厂模式

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 Product为抽象产品类负责定义产品的共性,实现对事物最抽象的定义; Creator为抽象创建类,也就是抽象工厂,具体如何创建产品类是由具体的实现工厂ConcreteCreator完成的。 java代码实现如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c){
             Product product=null;
             try {
                    product = (Product)Class.forName(c.getName()).newInstance();
             } catch (Exception e) {
                    //异常处理
             }
             return (T)product;         
     }
}

可以用以下的方法实例化各种产品:

1
2
3
ConcreteCreator factory = new ConcreteCreator();
ProductA productA =factory.createProduct(ProductA.class);
ProductB productB =factory.createProduct(ProductB.class);

单例模式

确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 /**
 * @author gravel 
 * 中国的历史上一般都是一个朝代一个皇帝
 * @date 2018-07-15
 */
public class Emperor {
	private static final Emperor emperor =new Emperor();  //初始化一个皇帝
	
	
	private Emperor(){
	    //这里限制只产生一个皇帝
		//世俗和道德约束你,目的就是不希望产生第二个皇帝
	}
	
	public static Emperor getInstance(){
		return emperor;
	}
	
	//皇帝发话了
	public static void say(){
		System.out.println("我就是皇帝某某某....");		
	}
}

单例模式主要分两种,一种是类加载时实例,一种是使用时实例。 另外在实际场景中Spring中创建的Bean实例默认都是单例模式存在的。 ### 建造者模式 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 在建造者模式中,有如下四个角色:

  • Product产品类:通常是实现了模板方法模式,也就是有模板方法和基本方法。
  • Builder抽象建造者:规范产品的组建,一般是由子类实现。
  • ConcreteBuilder具体建造者:实现抽象类定义的所有方法,并且返回一个组件好的对象。
  • Director导演:负责安排已有模块的顺序,然后告诉Builder开始建造。

这个模式我初次接触到的时候感觉有点抽象,我看到有大佬提到java的StringBuilder也是使用的建造者模式。

StringBuilder把构建者的角色交给了其的父类AbstractStringBuilder

1
2
3
4
5
6
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
。。。。。。
}

以append方法为例,最终调用的是父类的append():

1
2
3
4
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

父类AbstractStringBuilder的实现代码:

1
2
3
4
5
6
7
8
    public AbstractStringBuilder append(String str) {
        if (str == null) str = "null";
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;//返回构建对象
    }

结构型模式

在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等。对象结构的设计很容易体现出设计人员水平的高低,常用的几种结构型模式有: * 适配器模式 * 代理模式 * 装饰模式

适配器模式

将一个类的接口变换成客户端所期待的另一种接口,从而是原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 原有的接口,不能完全符合客户要求,但是我们有不能改
interface IOrigin{
    public void deal();
}
// 定义一个符合客户要求的新接口
interface ITarget{
    public void newDeal(int type);
}
class Target implements ITarget{
    private IOrigin origin;
    public void newDeal(int type){
        if (type==0){
        //这里调用原来的接口
            origin.deal();
        }else{
        //满足新的需求
        }
    }
}
public class TestAdapter {
    public  void test(){
        // 原来是IOrigin接口但是不符合我要求,所以用ITarget适配一下
        // 
        ITarget target = new Target();
        target.newDeal(1);
    }
}

代理模式

代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 一个顾客要买房
class Customer{
    public void sellHouse(){
    }
}
class Proxy {
    private Customer customer;
    public void buyHouse(){
        customer.sellHouse();
    }
}
public class TestProxy {
    public void test(){
        // 一个买家要买房的话直接跟中介(代理)大交道就可以了
        Proxy proxy = new Proxy();
        proxy.buyHouse();
    }
}

spring AOP也使用了动态代理的模式。

装饰模式

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更为灵活。 装饰模式在Java中最经典的应用就是I/O流,回忆一下,当我们使用流式操作读取文件内容时,怎么实现呢?示例如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public static void main(String[] args) throws IOException {
		DataInputStream dis = null;
		try {
			dis = new DataInputStream(
					new BufferedInputStream(
							new FileInputStream("E:/IOTest.txt")
							)
					);
			byte[] bs = new byte[dis.available()];
			dis.read(bs);
			System.out.println("文件内容====>"+new String(bs));
		} finally{
			dis.close();
		}
}

FileInputStream对象就相当于被装饰的对象,而BufferedInputStream对象和DataInputStream对象则相当于装饰器。

行为型模式

行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。 行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。 通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象 之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。 这里我就写一种:

观察者模式

建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应。在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加和删除观察者,使得系统更易于扩展,这就是观察者模式的模式动机。

在我们实际使用中,观察者模式应该比较多。比如消息队列之类的,比较经典的有Kafka中的订阅以及发布。

总结

Gof定义了23种设计模式,我这里只列了自己比较熟悉的几种,剩余的几种,比如迭代器,其实已经被java融合进jdk中,我们在开发中并不需要自己写。个人感觉设计模式的概念对于一些模块的重构和解耦帮助很大。学习不止!