创建型设计模式

  • 1、单例模式
  • 1.1 饿汉式 (静态常量)
  • 1.2 饿汉式(静态代码块)
  • 1.3 懒汉式 线程不安全
  • 1.4 懒汉式 线程安全,同步方法
  • 1.5 懒汉式 线程安全,同步代码块
  • 1.6 双重检查【推荐】
  • 1.7 静态内部类【推荐】
  • 1.8 枚举【推荐】
  • 2、工厂模式(简单工厂、工厂方法、抽象工厂)
  • 2.1 简单工厂
  • 2.2 工厂方法
  • 2.3 抽象工厂
  • 2.4 工作中常用工厂模式的形式
  • 3、原型模式
  • 4、建造者模式
  • 5、创建者模式对比
  • 5.1 工厂方法模式VS建造者模式
  • 5.2 抽象工厂模式VS建造者模式


1、单例模式

  所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例 ,并且该类只提供一个取得其对象实例的方法静态方法

1.1 饿汉式 (静态常量)

  结论:可用,类加载时创建,可能造成内存浪费。

class Singleton {
	//1. 构造器私有化, 外部能new
	private Singleton() {
	}
	//2.本类内部创建对象实例
	private final static Singleton instance = new Singleton();
	//3. 提供一个公有的静态方法,返回实例对象
	public static Singleton getInstance() {
		return instance;
	}
}
1.2 饿汉式(静态代码块)

  结论:同上

class Singleton {
	//1. 构造器私有化, 外部能new
	private Singleton() {
	}
	//2.本类内部创建对象实例
	private static Singleton instance;
	static { // 在静态代码块中,创建单例对象
		instance = new Singleton();
	}
	//3. 提供一个公有的静态方法,返回实例对象
	public static Singleton getInstance() {
		return instance;
	}
}
1.3 懒汉式 线程不安全

  结论:线程不安全,当两个线程都进入if判断,则创建两个实例。不是单例。

class Singleton {
	private static Singleton instance;
	private Singleton() {}
	//提供一个静态的公有方法,当使用到该方法时,才去创建 instance
	//即懒汉式
	public static Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}
1.4 懒汉式 线程安全,同步方法

  结论:线程安全,效率低。

// 懒汉式(线程安全,同步方法)
class Singleton {
	private static Singleton instance;
	private Singleton() {}
	//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
	//即懒汉式
	public static synchronized Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}
1.5 懒汉式 线程安全,同步代码块

   错误,同1.1.3 线程不安全,两个线程都进入if判断,则创建两个实例。不是单例。

1.6 双重检查【推荐】

   结论:推荐该方法

// 懒汉式(线程安全,同步方法)
class Singleton {
	private static volatile Singleton instance;
	private Singleton() {}
	//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
	//同时保证了效率, 推荐使用
	public static Singleton getInstance() {
		if(instance == null) {
			synchronized (Singleton.class) {
				if(instance == null) {
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
}
1.7 静态内部类【推荐】

   结论:推荐使用
  1、采用了类装载的机制来保证初始化实例时只有一个线程 。
  2、静态内部类方式在 Singleton 类被装载时并不会立即实例化,而是在需要实例化时,调用 getInstance 方法,才会装载。JVM 帮助我们保证了线程的安全性,在类进行初始化时,别的线程是无法进入的 。

// 静态内部类完成, 推荐使用
class Singleton {
	private static volatile Singleton instance;
	//构造器私有化
	private Singleton() {}
	//写一个静态内部类,该类中有一个静态属性 Singleton
	private static class SingletonInstance {
		private static final Singleton INSTANCE = new Singleton(); 
	}
	//提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
	public static synchronized Singleton getInstance() {
		return SingletonInstance.INSTANCE;
	}
}
1.8 枚举【推荐】

  结论:推荐使用。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象

//使用枚举,可以实现单例, 推荐
enum Singleton {
	INSTANCE; //属性
	public void sayOK() {
		System.out.println("ok~");
	}
}

2、工厂模式(简单工厂、工厂方法、抽象工厂)

2.1 简单工厂

【概念】:简单工厂模式是由一个工厂对象决定创建出哪一 种产品类 的实例 。简单工厂模式是工厂模式家族中最简单实用的模式
【结构】:抽象产品:定义了产品的规范,描述了产品的主要特性和功能。
     具体产品:实现或者继承抽象产品的子类
     具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品。
【缺点】:增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
【实现】:

public class SimpleCoffeeFactory {
    public Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffee;
    }
}

     静态工厂模式

public class SimpleCoffeeFactory {
    public static Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffe;
    }
}
2.2 工厂方法

【概念】:定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。
【结构】:抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
     具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
     抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
     具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
【缺点】:每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。产生类爆炸。
【实现】:

//抽象工厂
public interface CoffeeFactory {
    Coffee createCoffee();
}
//具体工厂
public class LatteCoffeeFactory implements CoffeeFactory {
    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}
public class AmericanCoffeeFactory implements CoffeeFactory {
    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}
//咖啡店类:
public class CoffeeStore {
    private CoffeeFactory factory;
    public CoffeeStore(CoffeeFactory factory) {
        this.factory = factory;
    }
    public Coffee orderCoffee() {
        Coffee coffee = factory.createCoffee();
        coffee.addMilk();
        coffee.addsugar();
        return coffee;
    }
}
2.3 抽象工厂

【概念】:抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
【缺点】:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。
【结构】:抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
     具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
     抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
     具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。
【实现】:

//抽象工厂
public interface DessertFactory {
    Coffee createCoffee();
    Dessert createDessert();
}
//具体工厂
//美式甜点工厂
public class AmericanDessertFactory implements DessertFactory {
    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
    public Dessert createDessert() {
        return new MatchaMousse();
    }
}
//意大利风味甜点工厂
public class ItalyDessertFactory implements DessertFactory {
    public Coffee createCoffee() {
        return new LatteCoffee();
    }
    public Dessert createDessert() {
        return new Tiramisu();
    }
}
2.4 工作中常用工厂模式的形式

简单工厂+配置文件解除耦合
工作实际开发中用到的工厂模式形式

3、原型模式

【概念】:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。
【结构】:抽象原型类:规定了具体原型对象必须实现的的 clone() 方法。
     具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
     访问类:使用具体原型类中的 clone() 方法来复制新的对象。
【分类】:浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型的属性,仍指向原有属性所指向的对象的内存地址。      深克隆:创建一个新对象,属性中引用的其他对象的属性也会被克隆,不再指向原有对象地址。
【实现】:1、浅克隆

//奖状类
public class Citation implements Cloneable {
    private Student stu;
    public Student getStu() {
        return stu;
    }
    public void setStu(Student stu) {
        this.stu = stu;
    }
    void show() {
        System.out.println(stu.getName() + "同学:在2020学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }
    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}
//测试类
public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation c1 = new Citation();
        Student stu = new Student("张三", "西安");
        c1.setStu(stu);
        //复制奖状
        Citation c2 = c1.clone();
        //获取c2奖状所属学生对象
        Student stu1 = c2.getStu();
        stu1.setName("李四");
        //判断stu对象和stu1对象是否是同一个对象
        System.out.println("stu和stu1是同一个对象?" + (stu == stu1));

        c1.show();
        c2.show();
    }
}

     2、深克隆

public class CitationTest1 {
    public static void main(String[] args) throws Exception {
        Citation c1 = new Citation();
        Student stu = new Student("张三", "西安");
        c1.setStu(stu);
        //创建对象输出流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\b.txt"));
        //将c1对象写出到文件中
        oos.writeObject(c1);
        oos.close();
        //创建对象出入流对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\b.txt"));
        //读取对象
        Citation c2 = (Citation) ois.readObject();
        //获取c2奖状所属学生对象
        Student stu1 = c2.getStu();
        stu1.setName("李四");
        //判断stu对象和stu1对象是否是同一个对象
        System.out.println("stu和stu1是同一个对象?" + (stu == stu1));
        c1.show();
        c2.show();
    }
}

4、建造者模式

【概念】:将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。如cpu、内存条以及显示屏等组装好电脑
【结构】:抽象建造者类(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不涉及具体的部件对象的创建。
     具体建造者类(ConcreteBuilder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。在构造过程完成后,提供产品的实例。
     产品类(Product):要创建的复杂对象。
     指挥者类(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
【缺点】:建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
【实现】:
     1、抽象建造者类(Builder):

// 抽象 builder 类
public abstract class Builder {
    protected Bike mBike = new Bike();//允许子类继承
    public abstract void buildFrame();
    public abstract void buildSeat();
    public abstract Bike createBike();
}

     2、具体建造者类(ConcreteBuilder)

public class MobikeBuilder extends Builder {
    @Override
    public void buildFrame() {
        mBike.setFrame("铝合金车架");
    }
    @Override
    public void buildSeat() {
        mBike.setSeat("真皮车座");
    }
    @Override
    public Bike createBike() {
        return mBike;
    }
}

     3、指挥者类(Director)

//指挥者类
public class Director {
    private Builder mBuilder;
    public Director(Builder builder) {
        mBuilder = builder;
    }
    public Bike construct() {
        mBuilder.buildFrame();
        mBuilder.buildSeat();
        return mBuilder.createBike();
    }
}

     4、简化系统结构,可以把指挥者类和抽象建造者进行结合

// 抽象 builder 类
public abstract class Builder {
    protected Bike mBike = new Bike();
    public abstract void buildFrame();
    public abstract void buildSeat();
    public abstract Bike createBike();
    public Bike construct() {
        this.buildFrame();
        this.BuildSeat();
        return this.createBike();
    }
}

【链式调用】

public class Phone {
    private String cpu;
    private String screen;
    private String memory;
    private String mainboard;
    private Phone(Builder builder) {
        cpu = builder.cpu;
        screen = builder.screen;
        memory = builder.memory;
        mainboard = builder.mainboard;
    }
    public static final class Builder {
        private String cpu;
        private String screen;
        private String memory;
        private String mainboard;
        public Builder() {}
        public Builder cpu(String val) {
            cpu = val;
            return this;
        }
        public Builder screen(String val) {
            screen = val;
            return this;
        }
        public Builder memory(String val) {
            memory = val;
            return this;
        }
        public Builder mainboard(String val) {
            mainboard = val;
            return this;
        }
        public Phone build() {
            return new Phone(this);}
    }
    @Override
    public String toString() {
        return "Phone{" +
                "cpu='" + cpu + '\'' +
                ", screen='" + screen + '\'' +
                ", memory='" + memory + '\'' +
                ", mainboard='" + mainboard + '\'' +
                '}';
    }
}
public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone.Builder()
                .cpu("intel")
                .mainboard("华硕")
                .memory("金士顿")
                .screen("三星")
                .build();
        System.out.println(phone);
    }
}

5、创建者模式对比

5.1 工厂方法模式VS建造者模式

  工厂方法模式注重的是整体对象的创建方式;而建造者模式注重的是部件构建的过程,意在通过一步一步地精确构造创建出一个复杂的对象。
  我们举个简单例子来说明两者的差异,如要制造一个超人,如果使用工厂方法模式,直接产生出来的就是一个力大无穷、能够飞翔、内裤外穿的超人;而如果使用建造者模式,则需要组装手、头、脚、躯干等部分,然后再把内裤外穿,于是一个超人就诞生了。

5.2 抽象工厂模式VS建造者模式