创建型模式之【单例模式】【工厂模式】【原型模式】【建造者模式】

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式包括
 (1)私有的构造方法
 (2)含有一个该类的静态私有对象private static
 (3)提供了一个静态的公有的函数用于创建或获取它本身的静态私有对象。

懒汉模式:全局的单例在第一次使用时构建(延迟初始化)

优点:
  避免了饿汉式的那种在没有用到的情况下创建事例,资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法。
缺点
   懒汉式在单个线程中没有问题,但多个线程同事访问的时候就可能同事创建多个实例,而且这多个实例不是同一个对象,虽然后面创建的实例会覆盖先创建的实例,但是还是会存在拿到不同对象的情况。解决这个问题的办法就是加锁synchonized,第一次加载时不够快,多线程使用不必要的同步开销大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton {
private Singleton(){
}
private static volatile Singleton instance = null;
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

饿汉模式:全局的单例实例在类装载时构建

  1.线程安全  
   2.在类加载的同时已经创建好一个静态对象,调用时反应速度快  
缺点

资源效率不高,可能getInstance()永远不会执行到,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个实例仍然初始化

1
2
3
4
5
6
7
8
9
public class Singleton {
private Singleton(){
}
private static volatile Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
}

单例模式的应用

  数据库连接池,多线程连接池。Windows应用管理器

优点

  • 1.在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就 防止其它对象对自己的实例化,确保所有的对象都访问一个实例
  • 2.单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
  • 3.提供了对唯一实例的受控访问
  • 4.由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
  • 5.允许可变数目的实例。
  • 6.避免对共享资源的多重占用。

缺点

单例模式可能导致内存泄漏(OOM)

  •  1.不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
    •  2.由于单利模式中没有抽象层,因此单例类的扩展有很大的困难
    •  3.单例类的职责过重,在一定程度上违背了“单一职责原则”
  •  4.滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

工厂模式

  定义一个用于创建对象的接口,让子类决定实例化哪个类,工厂方法使一个类的实例化延迟到其子类。
  提供一个创建对象实例的功能,而无须关心其具体实现。被创建实例的类型可以是接口、抽象类,也可以是具体的类。工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。

在这里插入图片描述

1.简单工厂方法

1
2
3
4
5
6
7
8
9
10
11
12
13
//创建工厂
public class Factory{
public static ISample creator(int which){
if (which==1)
return new SampleA();
else if (which==2)
return new SampleB();
}
}

//创建实例时
ISample sampleA = Factory.creator(1);
ISample sampleA = Factory.creator(2);

2.抽象工厂

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
//创建一个工厂接口
public abstract class Factory{
public abstract Sample creator();
public abstract Sample2 creator(String name);
}
//创建实现接口的实体类
public class SimpleFactory extends Factory{
public Sample creator(){
.........
return new SampleA
}
public Sample2 creator(String name){
.........
return new Sample2A
}
}
//创建工厂
public class BombFactory extends Factory{
public Sample creator(){
......
return new SampleB
}
public Sample2 creator(String name){
......
return new Sample2B
}
}

优点

 1、可以一定程度上解耦,消费者和产品实现类隔离开,只依赖产品接口(抽象产品),产品实现类如何改动与消费者完全无关。
 2、可以一定程度增加扩展性,若增加一个产品实现,只需要实现产品接口,修改工厂创建产品的方法,消费者可以无感知(若消费者不关心具体产品是什么的情况)。
 3、可以一定程度增加代码的封装性、可读性。清楚的代码结构,对于消费者来说很少的代码量就可以完成很多工作。

缺点

  每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖

应用场景

 1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。

 2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。

 3、设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。

原型模式

  创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式其实就是从一个对象再创建另外一个可定制的对象,而不需要知道任何创建细节

1.浅拷贝

  • 对类实现Cloneable接口(implements Cloneable),并且重写clone
  • 对值类型的成员变量进行值的复制,对引用类型的成员变量只复制引用,不复制引用的对象.
1
2
3
4
5
6
7
8
9
10
11
//具体原型类
class Realizetype implements Cloneable
{
Realizetype(){
System.out.println("具体原型创建成功!");
}
public Object clone() throws CloneNotSupportedException{
System.out.println("具体原型复制成功!");
return (Realizetype)super.clone();
}
}

2.深拷贝

  • 对其中的引用类型的成员变量进行实现Cloneable接口,重写clone,就变成深拷贝了
  • 对值类型的成员变量进行值的复制,对引用类型的成员变量也进行引用对象的复制
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class A implements Cloneable{
String name;

String int age;

Child child; //这是一个类,表A中的引用类型

@Override

public Object clone(){

try{

return super.clone();

}catch(Exception e){

}

return null;

}

}

public class child implements Cloneable{

@Override

public Object clone(){

try{

return super.clone();

}catch(Exception e){

}

return null;

}

}

优点

 1.如果创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程
 2.使用原型模式创建对象比直接 new 一个对象在性能上要好的多,因为 Object 类的 clone 方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。

使用场景

在需要重复地创建相似对象时可以考虑使用原型模式

  比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。

建造者模式

  将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示

模式的结构

  1. 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个部件。
  2. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
  3. 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
  4. 指挥者(Director):构建一个使用builder接口的对象。它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

使用场景

  主要用于创建一些复杂的对象,这些对象内部间的建造顺序是稳定的,但对象内部的构建通常面临着复杂的变化。

优点

 (1)使得建造代码与表示代码分离,由于建造者隐藏了产品如何组装,所以若需要改变一个产品内部表示,只需要在定义一个具体的建造者就可以了。

 (2) 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象

 (3)增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合 “开闭原则”

 (4)可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

文章目录
  1. 1. 单例模式
    1. 1.1. 懒汉模式:全局的单例在第一次使用时构建(延迟初始化)
    2. 1.2. 饿汉模式:全局的单例实例在类装载时构建
      1. 1.2.0.0.1. 缺点
  • 1.3. 单例模式的应用
  • 1.4. 优点
  • 1.5. 缺点
  • 2. 工厂模式
    1. 2.1. 1.简单工厂方法
    2. 2.2. 2.抽象工厂
    3. 2.3. 优点
    4. 2.4. 缺点
    5. 2.5. 应用场景
  • 3. 原型模式
    1. 3.1. 1.浅拷贝
    2. 3.2. 2.深拷贝
    3. 3.3. 优点
    4. 3.4. 使用场景
  • 4. 建造者模式
    1. 4.1. 模式的结构
    2. 4.2. 使用场景
    3. 4.3. 优点
  • | 139.6k