设计模式——创建型模式(创建对象)
设计模式——创建型模式(创建对象)
23种设计模式中创建型模式有以下⼏种:单例模式、⼯⼚模式、抽象⼯⼚模式、建造者模式、原型模式;创建型模式是处理对象创建的设计模式,根据实际情况使⽤合适的⽅式创建对象,将对象的创建和使⽤分离。
1、单例模式
使⽤单例模式创建对象的类只能有⼀个实例对象,那为什么要使⽤单例模式?使⽤new想创建⼏个对象就创建⼏个对象,为什么要使⽤单例模式去限制类的实例个数?
当⼀个全局类在系统中被频繁的使⽤时那就需要频繁的去使⽤new创建该类的对象,频繁的创建与销毁⼀个类的对象是⽐较消耗资源的。同时对于⼀些需要资源共享,或者在创建和销毁时⽐较消耗资源的资源(数据库连接)都建议使⽤单例模式。
1.1、单例模式的三种实现⽅式
1.1.1、饿汉式单例
饿汉式单例在加载类时就将对象创建好,但是这种⽅式可能存在资源浪费,如:对象在类加载后就创建好了,如果在程序运⾏期间该对象并没有被使⽤就会造成资源浪费。
饿汉式单例的创建⽅式:
/**
* @Description:饿汉式单例模式
* @Author: guai
* @Date:2020/9/14 15:31
**/
public class HungryMode {
/*单例模式存在的问题?
1、线程不安全;
2、类加载时就创建了对象,但创建的对象最终未必会被使⽤,导致内存占⽤;
private byte[] data1=new byte[100];*/
//1、构造函数私有化
private HungryMode(){}
//2、在类加载时就创建好该类的对象;
private final static HungryMode HUNGRY_MODE=new HungryMode();
//3、外部通过静态⽅法获取该类的对象
public static HungryMode getHungryMode(){
return HUNGRY_MODE;
}
}
1.1.2、懒汉式单例
懒汉式单例是当该类的对象被需要时再创建,懒汉式单例存在的问题是在对象尚未被创建时被多个其它对象同时访问,此时懒汉式单例在创建对象时就会存在线程安全的问题。
1. 线程不安全的懒汉式单例的创建⽅式:
/**
* @Description:验证懒汉模式单例是线程不安全的
* @Author: guai
* @Date:2020/9/30 9:58
**/
public class LazyModeVerify {
//私有化构造器
private LazyModeVerify(){
System.out.println("create");
}
//定义私有对象
private static LazyModeVerify LAZYMODEVERIFY;
//通过访问器当需要使⽤该对象时创建(当对象实例没有初始化时)并获取对象
public static LazyModeVerify getLAZYMODEVERIFY(){
if(LAZYMODEVERIFY==null){
LAZYMODEVERIFY=new LazyModeVerify();
}
return LAZYMODEVERIFY;
}
public static void main(String[] args){
//当LazyModeVerify的实例对象为空时使⽤多线程去获取LazyModeVerify对象时该对象可能会被创建多次
for(int i=0;i<10;i++){
new Thread(()->{
}).start();
}
}
}
结果:
单例模式的几种实现方式此时因为在多线程访问getLAZYMODEVERIFY()之前对象已被创建不会出现对象被多次被创建的情况。
当注释掉(1)处代码的结果:
此时因为在多线程访问时对象还没被创建,在多个线程同时访问getLAZYMODEVERIFY()时存在多个线程都进⼊if语句中导致多个实例对象被创建。
2. 线程安全的懒汉式单例的创建
/**
* @Description:线程安全的单例模式
* @Author: guai
* @Date:2020/9/30 9:58
**/
public class LazyModeVerify {
//私有化构造器
private LazyModeVerify(){
System.out.println("create");
}
//定义私有对象
//volatile 可以禁⽌指令重排防⽌在创建对象时出现指令重排导致程序出错。
//如果发⽣指令重排如⼀个线程在执⾏了1,3后此时LAZYMODEVERIFY已不为null;
//另⼀个线程直接来获取LAZYMODEVERIFY并调⽤⽅法此时LAZYMODEVERIFY对象并没有被创建完成将会导致错误/*对象在创建时⼤致分为三步:
1、分配栈内存空间
2、调⽤构造⽅法创建对象实例
3、将栈中对象的引⽤指向堆内存中的地址*/
private static volatile LazyModeVerify LAZYMODEVERIFY;
//通过访问器当需要使⽤该对象时创建(当对象实例没有初始化时)并获取对象
public static LazyModeVerify getLAZYMODEVERIFY(){
if(LAZYMODEVERIFY==null){
//加锁
//双重检测锁模式的懒汉式单例 DCL懒汉式
synchronized(LazyMode.class){
if(LAZYMODEVERIFY == null){
LAZYMODEVERIFY=new LazyModeVerify();
}
}
}
return LAZYMODEVERIFY;
}
public static void main(String[] args){
for(int i=0;i<10;i++){
new Thread(()->{
LazyModeVerify lazyModeVerify= LAZYMODEVERIFY();
}).start();
}
}
}
结果:
1.1.3、通过枚举来实现单例
为什么要使⽤枚举实现单例模式?
我们来看下⾯的代码:
/**
* @Description:为啥要使⽤枚举实现单例
* @Author: guai
* @Date:2020/9/30 10:48
**/
public class EnumSingleVerify {
//私有化构造函数
private EnumSingleVerify(){
System.out.println("create me");
}
private static EnumSingleVerify enumSingleVerify=new EnumSingleVerify();
public static EnumSingleVerify getEnumSingleVerify(){
return enumSingleVerify;
}
public static void main(String[] args)throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { System.out.println(getEnumSingleVerify().toString());
//通过反射破坏单例模式
//获取EnumSingleVerify的构造函数
Constructor constructor=DeclaredConstructor();
constructor.setAccessible(true);
//创建对象
EnumSingleVerify enumSingleVerify=(EnumSingleVerify) wInstance();
System.out.String());
}
}
结果: 成功通过反射创建了使⽤单例模式的EnumSingleVerify类
接下来我们通过枚举实现单例模式来防⽌反射的破坏:
/**
* @Description:通过枚举来防⽌反射破坏单例
* @Author: guai
* @Date:2020/9/30 12:22
**/
public class EnumSinglePractice {
private EnumSinglePractice(){}
//enum的本质还是⼀个类
static enum SingletonEnum{
//创建⼀个枚举对象,该对象天⽣单例,
INSTANCE;
private EnumSinglePractice enumSinglePractice=new EnumSinglePractice();
public EnumSinglePractice instance(){
return enumSinglePractice;
}
}
public void say(){
System.out.println("jsut me");
}
}
class EnumSingleTest{
public static void main(String[] args)throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { EnumSinglePractice enumSinglePractice= EnumSinglePractice.SingletonEnum.INSTANCE.instance();
enumSinglePractice.say();
Constructor constructor=EnumSinglePractice.DeclaredConstructor(String.class,int.class);
Constructor[] constructors=EnumSinglePractice.DeclaredConstructors();
constructor.setAccessible(true);
EnumSinglePractice.SingletonEnum singletonEnum=(EnumSinglePractice.wInstance();
}
}
结果:
我们来瞅⼀下为啥不能通过反射来创建单例模式: 在newInstance()中会进⾏判断当为enum类型时,会抛出异常。
2、建造者
2.1、构建者模式
将产品的构造和表⽰分离,实现了解耦。将负责的产品的创建步骤分解在不同的⽅法中,使创建过程更加清晰。
构建者模式⼀般有4个⾓⾊:Product(最终⽣成的对象),Builder(构造者的抽象基类),ConcreteBuilder(Builder的实现类)、Director(决定如何构建最终产品)
Product(最终⽣成的对象)
package ate.builder.demo1;
public class Product {
private String buildA;
private String buildB;
private String buildC;
public String getBuildA(){
return buildA;
}
public void setBuildA(String buildA){
this.buildA = buildA;
}
public String getBuildB(){
return buildB;
}
public void setBuildB(String buildB){
this.buildB = buildB;
}
public String getBuildC(){
return buildC;
}
public void setBuildC(String buildC){
this.buildC = buildC;
}
@Override
public String toString(){
return"Product{"+
"buildA='"+ buildA +'\''+
", buildB='"+ buildB +'\''+
", buildC='"+ buildC +'\''+
'}';
}
}
Builder(构造者的抽象基类):
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论