设计模式之创建型

158 阅读5分钟

「这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战

创建型模式,主要是用于组件对象的创建,

image.png   

 主要有五种:

  1. 单例模式,(在系统中有且只有一个对象)
  2. 工厂方法模式
  3. 抽象工厂模式
  4. 建造者模式(工人可能关注与创建对象的细节过程)
  5. 原型模式(克隆一个爱因斯坦)

2.单例模式:(Singleton)

image.png

  单例的有且只有一个实例对象

要点:

创建-构造器私有

可以外部访问

静态;

**
**

我自己写的是这样的:

 

package com.atlucas.creation.singleton;
/**
 * @author lucas
 * @create 2021-03-18 15:01
 * @description  单例模式的实体类
 */
public class Person {
    private String name;
    private  Integer age;
    /**
     * 单例模式;要求此系统中有且只有一个实例对象;
     *
     *  1.确定是饿汉式还是懒汉式,然后创建一个静态的私有变量
     *  2.构造器私有化
     *  3.外部访问对象,要从我们自己构造好的私有对象返回       *
     */
 
    /**
     * 1.确定是饿汉式还是懒汉式,然后创建一个静态的私有变量
     * private  static final  Person Instanc=new Peson(); 饿汉式,不让变动
     */
    private  static   Person Instance;   //懒汉式时间换空间
    /**
     * 2.构造器私有化
     */
    private Person (){
        System.out.println("需要创建一个对象person");
    }
    /**3.外部访问
     * 公共的静态方法-->利用静态存储方法区,
     * 建立一个静态的空对象,如果需要就一直存在,直至程序完结
     * @return
     */
    public static Person getPerson(){
        //多线程情况下不安全
        if (Instance==null){
            Person person=new Person();
            Instance=person;
        }
    return Instance;
    }
    public static void main(String[] args) {
       //静态的公共获取方法--对象都一样
        Person person1 = Person.getPerson();
        Person person2 = Person.getPerson();
        System.out.println(person1==person2);
    }
}


\

上述的情况在于多线程的是不安全的;

\

\

优化一:

\

 

 /**3.外部访问
     * 公共的静态方法-->利用静态存储方法区,
     * 建立一个静态的空对象,如果需要就一直存在,直至程序完结
     * @return
     */
    public static synchronized Person getPerson(){
        //多线程情况下不安全
        if (Instance==null){
            Person person=new Person();
            Instance=person;
        }
    return Instance;
    }

\

\

优化二: 

\

2.1标准的单例模式:

 

package com.atlucas.creation.singleton;
/**
 * @author lucas
 * @create 2021-03-18 15:01
 * @description  单例模式的实体类
 */
public class Person {
    private String name;
    private  Integer age;
    /**
     * 单例模式;要求此系统中有且只有一个实例对象;
     *
     *  1.确定是饿汉式还是懒汉式,然后创建一个静态的私有变量
     *  2.构造器私有化
     *  3.外部访问对象,要从我们自己构造好的私有对象返回       *
     */
    /**
     * 1.确定是饿汉式还是懒汉式,然后创建一个静态的私有变量
     * private  static final  Person Instanc=new Peson(); 饿汉式,不让变动
     */
    private  static  volatile Person Instance;
    /**
     * 2.构造器私有化
     */
    private Person (){
        System.out.println("需要创建一个对象person");
    }
    /**3.外部访问
     * 公共的静态方法-->利用静态存储方法区,
     * 建立一个静态的空对象,如果需要就一直存在,直至程序完结
     * @return
     */
    public static  Person getPerson(){
        //多线程情况下不安全
        if (Instance==null){
            synchronized (Person.class){
                //同步代码块+双重检查锁(+ volatile内存可见性,创建对象防止指令重排序)
                if (Instance==null){
                Person person=new Person();
                Instance=person;
            }}
        }
    return Instance;
    }
    public static void main(String[] args) {
       //静态的公共获取方法--对象都一样
        Person person1 = Person.getPerson();
        Person person2 = Person.getPerson();
        System.out.println(person1==person2);
    }
}

\

对于单列模式:基本是双重锁+内存可见性

**
**

**
**

**
**

2.2.单例模式的适用场景:

系统信息,环境变量的基础信息:

**
**

**
**

**
**

3.原型模式:(Prototype)

创建很多重复的对象,不影响性能;

  

\

比如我们查询相同的数据, 如果mybatis查询数据库,很多相同的记录,是多个相同的user

\

\

 原型模式,主要是利于缓存,-->每次返回一个不一样的克隆体供我们使用

\

本体给外部返回一个克隆体

**
**

**
**

深拷贝和浅拷贝

**
**

 

package com.atlucas.creation.prototype;
import javax.jws.soap.SOAPBinding;
import java.util.HashMap;
/**
 * @author lucas
 * @create 2021-03-18 16:38
 * @description  测试原型模型,创建相同的属性对象,但不会影响性能
 */
public class TestProtoType {
 public static    HashMap <String,User> prototypeCache=new HashMap<String, User>();
    public User getUser() throws CloneNotSupportedException {
        //缓存,相同的数据再缓存中拿取出来
        /**
         * 比如我们查询一个名称,给我们返回一个数据记录
         */
        TestProtoType type = new TestProtoType();
        //缓存中不存在
        if (!prototypeCache.containsKey("lucas")) {
            //从数据库取出来
            User user = TestProtoType.getUserfromDB();
            return user;
        } else {
            User user = prototypeCache.get("1");
            //拿到原型之后--->实现克隆体
            User clone = (User) user.clone();
            return  clone;
        }
    }
    //获取数据库的数据对象
    private static User getUserfromDB() throws CloneNotSupportedException {
        System.out.println("获取数据库中的对象");
        User user=new User();
        user.setUserName("lucas");
        user.setAge(23);
        user.setUserID("10086123");
        //放入缓存,原型-->克隆体,所以每次获取都会创建一个克隆体
        User put = prototypeCache.put("1", (User) user.clone());
        return user;
    }
    public static void main(String[] args) throws CloneNotSupportedException {
        TestProtoType t1=new TestProtoType();
        User user = t1.getUser();
        TestProtoType t2=new TestProtoType();
        User user1 = t2.getUser();
        System.out.println(user==user1);
    }
}

\

\

package com.atlucas.creation.prototype;
import netscape.security.UserDialogHelper;
import javax.jws.soap.SOAPBinding;
/**
 * @author lucas
 * @create 2021-03-18 16:39
 * @description  对于使用一个原型模式的
 *      比如基本创建多个相同的对象,但是不会影响性能
 */
public class User  {
    private String userName;
    private  Integer age;
    private String UserID;
    public  User(){
        System.out.println("创建一个user对象");
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getUserID() {
        return UserID;
    }
    public void setUserID(String userID) {
        UserID = userID;
    }
    @Override
    public String toString() {
        return "User{" +
                "userName='" + userName + ''' +
                ", age=" + age +
                ", UserID='" + UserID + ''' +
                '}';
    }
    /**
     * 重写克隆方法
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        User user=new User();
        //放入对象属性,浅拷贝-对象的内存指向没有变化
        user.setAge(this.age);
        user.setUserID(this.UserID);
        user.setUserName(this.userName);
        return user.clone();
    }
}