xiaobenchi

导航

设计模式之创建型2

本文学习自大话设计模式

设计模式之创建型

1. 单例模式

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式有5种基本实现方式。

  • 饿汉单例

    线程安全,非懒加载,直接创建实例

    public class EhSingleton{
        
        private static EhSingleton ehSingleton = new EhSingleton();
        
        private EhSingleton(){}
        
        public static EhSingleton getInstance(){
            return ehSingleton;
        }
    }
    

    缺点:类加载就初始化,浪费内存。

    优点:没有加锁,执行效率高,线程安全。

  • 懒汉单例

    线程不安全,懒加载

    public class LazySingleton{
        
        private static LazySingleton lazySingleton;
        
        private LazySingleton(){}
        
        public static LazySingleton getInstance(){
            if(lazySingleton == null){
                lazySingleton = new LazySingleton();
            }
            return lazySingleton;
        }
    }
    
  • 加同步锁的懒汉单例

    线程安全,懒加载

    public class LazySingletonSync{
        
        private static LazySingleSync lazySingletonSync;
        
        private LazySingletonSync(){}
        
        public static synchronized LazySingletonSync getInstance(){
            if(lazySingletonSync == null){
                lazySingletonSync = new LazySingletonSync();
            }
            return lazySingletonSync;
        }
    }
    

    问题:效率低,只有第一次调用初始化之后才需要同步,初始化之后都不需要同步。锁的粒度太大,影响程序的执行效率。

  • 双重检验懒汉单例

    线程安全,懒加载

    使用synchronized声明的方法,在多线程访问时,其他线程必须等待前面的线程执行完毕之后才能访问,降低了程序的执行效率,这个时候使用synchronized代码块优化执行时间,减小锁的粒度。

    public class LazySingletonDoubleCheck{
        
        private static LazySigletonDoubleCheck lazySingletonDoubleCheck;
        
        private LazySingletonDoubleCheck(){}
        
        public static LazySingletonDoubleCheck getInstance(){
            if(lazySingletonDoubleCheck == null){
                scnchronized(LazySingletonDoubleCheck.class){
                    if(lazySingleDoubleCheck == null){
                        lazySigletonDoubleCheck = new LazySingletonDoubleCheck();
                    }
                }
            }
            return lazySingletonDoubleCheck;
        }
    }
    
  • 静态内部类

    线程安全,懒加载

    public class StaticClass {
     
        private StaticClass() {}
     
        private static class SingletonHolder {
            private static final SingletonHolder INSTANCE = new SingletonHolder();
        }
     
        public static final SingletonHolder getInstance() {
            return SingletonHolder.INSTANCE;
        }
    }
    

2. 建造者模式

建造者模式就是一个规范化的过程。要使用到抽象的类来定义基本的模块。

建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

  • 建造者模式的结构图

    image-20220720114205422

    Builder:建造产品各个部分的抽象类;

    ConcreteBuilder:具体的产品,实现抽象类中定义的各个部分;

    Director:指挥者,构建一个使用Builder接口的对象;

  • 建造房子为例

    • 复杂房屋类
    //复杂产品房子
    public class House {
    	private String baise;
    	private String wall;
    	private String roofed;
    	public String getBaise() {
    		return baise;
    	}
    	public void setBaise(String baise) {
    		this.baise = baise;
    	}
    	public String getWall() {
    		return wall;
    	}
    	public void setWall(String wall) {
    		this.wall = wall;
    	}
    	public String getRoofed() {
    		return roofed;
    	}
    	public void setRoofed(String roofed) {
    		this.roofed = roofed;
    	}
    }
    
    • Bulider抽象类

      //抽象建设者,主要用来指定建设步骤
      public abstract class HouseBuilder {
      	protected House house = new House();
      	//建设房屋的基本方法,建设根基、建设墙、建设屋顶
      	public abstract void buildBasic();
      	public abstract void buildWalls();
      	public abstract void roofed();
      	public House buildHouse() {
      		return house;
      	}
      }
      
    • 两个实现类

      //高楼大厦
      public class HighBuilding extends HouseBuilder{
      	@Override
      	public void buildBasic() {
      		System.out.println("高楼地基");
      	}
      	@Override
      	public void buildWalls() {
      		System.out.println("高楼墙面");
      	}
      	@Override
      	public void roofed() {
      		System.out.println("高楼屋顶");
      	}
      }
      
      //普通房屋
      public class CommonHouse extends HouseBuilder{
      	@Override
      	public void buildBasic() {
      		System.out.println("普通房子基地");
      	}
      	@Override
      	public void buildWalls() {
      		System.out.println("普通房子墙面");
      	}
      	@Override
      	public void roofed() {
      		System.out.println("普通房子屋顶");
      	}
      }
      
    • Director类

      public class HouseDirector{
          HouseBuilder houseBuilder = null;
          //构造器创建bilder对象
          public HouseBuilder(HouseBuilder houseBuilder){
              this.houseBuilder = houseBuilder;
          }
          //通过set方法设置对象属性
          public void setHouseBuilder(HouseBuilder houseBuilder){
              this.houseBuilder = houseBuilder;
          }
          //建造房屋的流程交给指挥者
          public House constructHouse(){
              hosueBuilder.buildBasic();
              houseBuilder.buildWalls();
              houseBuilder.roofed();
              return houseBuilder.buildHouse();
          }
      }
      

3. 原型模式

原型模式(Prototype),用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

  • 原型模式结构图

    image-20220720121124924

    原型模式其实就是从一个对象再创建另外一个可定制的对象,而且不需要知道任何创建的细节。

    • 抽象原型类(Prototype):规定了具体原型对象必须实现的接口。
    • 具体原型类(ConcretePrototype):实现抽象原型类的clone方法,它是被复制的对象。
    • 访问类(Client):使用具体的原型类中的clone方法来复制新的对象
  • 原型模式的例子

    • 原型类代码

      重点是实现Cloneable接口以及重写clone方法

      public class Prototype implements Cloneable, Serializable {
       
          private String name;
          private int age;
          private RefObject refObject;
       
          public Prototype(String name, int age) {
              this.name = name;
              this.age = age;
          }
       
          public RefObject getRefObject() {
              return refObject;
          }
       
          public void setRefObject(RefObject refObject) {
              this.refObject = refObject;
          }
       
          public String getName() {
              return name;
          }
       
          public void setName(String name) {
              this.name = name;
          }
       
          public int getAge() {
              return age;
          }
       
          public void setAge(int age) {
              this.age = age;
          }
       
          //重写克隆方法 默认浅拷贝
          @Override
          protected Object clone() throws CloneNotSupportedException {
              Prototype clone = (Prototype) super.clone();
              return clone;
          }
         
       
          @Override
          public String toString() {
              return "Prototype{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      ", refObject=" + refObject +
                      '}';
          }
      }
      
    • 客户端main方法

       public static void main(String[] args) throws CloneNotSupportedException {
              Prototype prototype = new Prototype("原型模板",2);
              prototype.setRefObject(new RefObject());
              Prototype clone1 = (Prototype) prototype.clone();
              Prototype clone2 = (Prototype) prototype.clone();
              System.out.println(clone1);
              System.out.println(clone2);
              System.out.println("原型 hashCode"+prototype.getRefObject().hashCode());
              System.out.println("浅克隆  hashCode"+clone1.getRefObject().hashCode());
              System.out.println("浅克隆  hashCode"+clone2.getRefObject().hashCode());
              System.out.println(prototype.getRefObject()==clone1.getRefObject());
              System.out.println(prototype.getRefObject()==clone2.getRefObject());
          }
      
  • 原型模式深拷贝

     //深拷贝 利用反序列 和序列化
        @Override
        protected Object clone() {
            //序列化 将当前对象序列化到内存中
            ByteArrayOutputStream byteArrayOutputStream;
            ObjectOutputStream oos = null;
            ObjectInputStream ois = null;
            try {
                byteArrayOutputStream = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(byteArrayOutputStream);
                oos.writeObject(this);
                //反序列化
                byte[] bytes = byteArrayOutputStream.toByteArray();
                ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
                ois = new ObjectInputStream(bis);
                return ois.readObject();
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                if (oos != null) {
                    try {
                        oos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (ois != null) {
                    try {
                        ois.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
     
            return null;
        }
    
  • 原型模式的优缺点

    • 优点:
      1. java自带的原型模式基于内存二进制流的复制,在性能上比new一个对象更加优良。
      2. 可以使用深拷贝保存对象的状态,以便后续使用。
    • 缺点:
      1. 在java中需要为每个类都配置一个clone方法。
      2. clone方法位于类内部,改造类的时候需要修改代码。
      3. 深拷贝的实现比较复杂,需要每一层对象对应的类都需要支持深拷贝。

posted on 2022-07-20 12:41  小迟在努力  阅读(20)  评论(0)    收藏  举报