【设计模式】享元模式

享元模式(Flyweight Pattern)

享元模式:主要用于减少创建对象的数量,以减少内存占用和提高性能;String常量池以及数据库连接池是享元模式的应用实例

含义: 享元模式会尝试重用现有的同类对象,如果未找到匹配的对象,才会进行创建对象的操作。
应用场景: 在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

优点: 大大减少对象的创建,降低系统的内存,使效率提高
缺点: 提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱

内部状态指对象共享出来的信息,存储在享元对象内部并且不会随环境的改变而改变;
外部状态指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。

代码演示

public class TestString {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "abc";
        String s3 = new String("abc");
        String s4 = new String("abc");

		// abc 存在于常量池中,s1 s2都是指向常量池中abc的引用
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);
        System.out.println(s3 == s4);
        System.out.println(s3.intern() == s1);
        System.out.println(s3.intern() == s4.intern());
    }
}

验证结果

true
false
false
true
true

s3.intern() : 在常量池中尝试获取是否存在s3对应值的引用,如果常量池中存在,则返回该引用

代码演示:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;

class Bullet{
    public UUID id = UUID.randomUUID();
    boolean living;

    @Override
    public String toString() {
        return "Bullet{" +
                "id=" + id +
                '}';
    }
}

public class BulletPool {
    List<Bullet> bullets = new ArrayList<>();
    {
        for(int i=0; i < 5; i++) {
            bullets.add(new Bullet());
        }
    }

    public Bullet getBullet() {
        Random random = new Random();
        int i = random.nextInt(bullets.size());
        Bullet b = bullets.get(i);
        if(i % 2 == 0){
            b.living = false;
        } else {
            b.living = true;
        }
        if(!b.living) {
            return b;
        } else {
            return new Bullet();
        }
    }

    public static void main(String[] args) {
        BulletPool bp = new BulletPool();
        System.out.println(bp.bullets.toString());
        System.out.println("==========================");
        for(int i=0; i<5; i++) {
            Bullet b = bp.getBullet();
            System.out.println(b);
        }
    }
}

测试结果

[Bullet{id=08453500-8d78-4728-8211-218621de8dae},
 Bullet{id=da537e07-4157-4892-b257-f1902ebec213}, 
 Bullet{id=cfc2ce30-9bef-4586-be46-ec82a542e1a7}, 
 Bullet{id=17e3a563-aec5-444c-b8ba-6bf0d96c0891}, 
 Bullet{id=35388758-3af1-4419-b190-1a3a36ff7de2}]
==========================
Bullet{id=08453500-8d78-4728-8211-218621de8dae}
Bullet{id=08453500-8d78-4728-8211-218621de8dae}
Bullet{id=35388758-3af1-4419-b190-1a3a36ff7de2}
Bullet{id=cfc2ce30-9bef-4586-be46-ec82a542e1a7}
Bullet{id=a0478bd3-aa22-4ae6-a019-ae9c787b3aff}

注意事项:
1,实例需要注意划分内部状态和外部状态,否则可能会引起线程安全问题
2,这些类必须有一个工厂类加以控制

你可能感兴趣的:(设计模式)