单例

因为单例迟早是要实例化的,延迟懒加载的加锁反而会造成资源浪费,同步问题会降低CPU利用率,因此一般采用饿汉模式

饿汉模式

在类加载时就初始化对象,之后一直返回这个对象。

  1. public class Sun {
  2. /**
  3. * static确保在类加载时初始化,在内存中永存,不会被GC回收;final确保是常量,引用一旦被赋值就无法更改
  4. */
  5. private static final Sun sun = new Sun();
  6. /**
  7. * 私有构造,封闭太阳类使得外部类无法干预内部的实例化
  8. */
  9. private Sun() {
  10. }
  11. /**
  12. * 由于构造私有,static是为了保证能调用此方法
  13. */
  14. public static Sun getInstance() {
  15. return sun;
  16. }
  17. }

懒汉模式

第一次需要时创建对象,之后一直使用这个对象,不再重复创建。

  1. public class Sun {
  2. /**
  3. * 保证各线程副本数据与公共内存中保持一致
  4. */
  5. private volatile static Sun sun;
  6. private Sun() {
  7. }
  8. public static Sun getInstance() {
  9. // 此处加个判断是为了在已赋值情况下直接返回对象,无需让线程再等待
  10. if (sun == null) {
  11. // 加锁,让多线程排队等待
  12. synchronized (Sun.class) {
  13. // 此处是为了保证轮到其他线程后,防止太阳对象再次被赋值
  14. if (sun == null) {
  15. sun = new Sun();
  16. }
  17. }
  18. }
  19. return sun;
  20. }
  21. }
  1. public class Main {
  2. public static void main(String[] args) {
  3. Sun eagerSun01 = Sun.getInstance();
  4. Sun eagerSun02 = Sun.getInstance();
  5. D01Singleton.lazy.Sun lazySun01 = D01Singleton.lazy.Sun.getInstance();
  6. D01Singleton.lazy.Sun lazySun02 = D01Singleton.lazy.Sun.getInstance();
  7. System.out.println(eagerSun01 == eagerSun02); //true
  8. System.out.println(lazySun01 == lazySun02); //true
  9. }
  10. }

原型

从原型实例克隆创建对象,而不是用类创建对象。对于有非常复杂的初始化过程的对象或者是需要耗费大量资源时,可采用原型模式。

实现原型模式的关键在于拷贝(克隆),拷贝分为浅拷贝和深拷贝,因此原型模式拷贝也有两种,想要实现什么样的原型模式视情况决定。

浅拷贝、深拷贝

Java中的变量分为原始类型和引用类型浅拷贝是值拷贝,它会复制原始类型的值和引用类型的地址引用,因此复制后的引用类型对象和被复制的引用类型对象会是同一对象。Java中的父类Object的clone方法就是浅拷贝。

深拷贝就是在浅拷贝的基础上,将引用类型完全复制一份,复制前后的两个对象不是同一地址引用。

Java实现

Java中的实现通过实现cloneable接口即可实现原型模式。

浅拷贝

  1. public class Bullet implements Cloneable {
  2. private int speed;
  3. public Bullet(int speed) {
  4. this.speed = speed;
  5. }
  6. public int getSpeed() {
  7. return speed;
  8. }
  9. public void setSpeed(int speed) {
  10. this.speed = speed;
  11. }
  12. /**
  13. * 需要注意返回是Bullet对象,默认重写方法是Object
  14. */
  15. @Override
  16. protected Bullet clone() throws CloneNotSupportedException {
  17. return (Bullet) super.clone();
  18. }
  19. }
  1. public class EnemyPlaneShallow implements Cloneable {
  2. private int x;
  3. private int y = 0;
  4. private Bullet bullet;
  5. public EnemyPlaneShallow(int x, Bullet bullet) {
  6. this.x = x;
  7. this.bullet = bullet;
  8. }
  9. public int getX() {
  10. return x;
  11. }
  12. public void setX(int x) {
  13. this.x = x;
  14. }
  15. public int getY() {
  16. return y;
  17. }
  18. public void fly() {
  19. y++;
  20. }
  21. public Bullet getBullet() {
  22. return bullet;
  23. }
  24. public void setBullet(Bullet bullet) {
  25. this.bullet = bullet;
  26. }
  27. @Override
  28. protected EnemyPlaneShallow clone() throws CloneNotSupportedException {
  29. return (EnemyPlaneShallow) super.clone();
  30. }
  31. }

深拷贝

  1. public class EnemyPlaneDeep implements Cloneable {
  2. private int x;
  3. private int y = 0;
  4. private Bullet bullet;
  5. public EnemyPlaneDeep(int x, Bullet bullet) {
  6. this.x = x;
  7. this.bullet = bullet;
  8. }
  9. public int getX() {
  10. return x;
  11. }
  12. public void setX(int x) {
  13. this.x = x;
  14. }
  15. public int getY() {
  16. return y;
  17. }
  18. public void fly() {
  19. y++;
  20. }
  21. public Bullet getBullet() {
  22. return bullet;
  23. }
  24. public void setBullet(Bullet bullet) {
  25. this.bullet = bullet;
  26. }
  27. @Override
  28. protected EnemyPlaneDeep clone() throws CloneNotSupportedException {
  29. EnemyPlaneDeep plane = (EnemyPlaneDeep) super.clone();
  30. plane.setBullet(this.bullet.clone()); // 对引用类型单独进行深拷贝
  31. return plane;
  32. }
  33. }

测试

  1. public class Main {
  2. public static void main(String[] args) throws CloneNotSupportedException {
  3. EnemyPlaneShallow planeShallow = new EnemyPlaneShallow(10, new Bullet(11));
  4. EnemyPlaneShallow planeShallowClone = planeShallow.clone();
  5. System.out.println(planeShallow.getBullet() == planeShallowClone.getBullet()); // true
  6. EnemyPlaneDeep planeDeep = new EnemyPlaneDeep(10, new Bullet(11));
  7. EnemyPlaneDeep planeDeepClone = planeDeep.clone();
  8. System.out.println(planeDeep.getBullet() == planeDeepClone.getBullet()); // false
  9. }
  10. }