设计模式-工厂和单例模式

概念和作用

分类

7大原则

工厂模式
概念
工厂模式是创建型模式,它是对象创建的最佳方案,特别是创建对象过程比较复杂。(如果理解new对象就可以完成功能,不需要用工厂模式)。
好处
实现对象的创建和使用的解耦。
分类
简单工厂模式简单工厂模式
简介
也叫静态工厂模式,可以根据不参数创建不同的对象,被创建的对象都要有相同接口或者父类。
实战
需求
假如AAA是一个工厂,课程看成产品,使用AAA工厂创建不同的课程!
代码
接口及实现类

package com.aaa.dp.factory.simple;

/**
 * @FileName: SoftwareTechnology
 * @Description: 软件技术接口
 * @Author: zhz
 * @CreateTime: 2024/11/27 10:49
 * @Version: 1.0.0
 */
public interface SoftwareTechnology {

    /**
     * 学习课程的方法
     */
    void  studyST();
}


package com.aaa.dp.factory.simple;

/**
 * @FileName: JavaDev
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 10:51
 * @Version: 1.0.0
 */
public class JavaDev implements SoftwareTechnology{
    @Override
    public void studyST() {
        System.out.println("头悬梁,锥刺股努力学习java开发技术,高薪就业,将来当上CTO,迎娶白富美/高富帅......走上人生巅峰!");
    }
}

package com.aaa.dp.factory.simple;

/**
 * @FileName: PythonDev
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 10:54
 * @Version: 1.0.0
 */
public class PythonDev  implements  SoftwareTechnology{
    @Override
    public void studyST() {
        System.out.println("头悬梁,锥刺股努力学习Python开发技术,高薪就业,将来当上CTO,迎娶白富美/高富帅......走上人生巅峰!");
    }
}

工厂类

package com.aaa.dp.factory.simple;

/**
 * @FileName: AAAFactory
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 10:55
 * @Version: 1.0.0
 */
public class AAAFactory {

    /**
     * 教授课程的方法
     * @param type
     * @return
     */
    public  static  SoftwareTechnology   teachST(int type){
       //判断  参数不同  返回值不同
        if(type==1){
            return new JavaDev();
        } else if (type==2) {
            return new CDev();
        } else if (type==3) {
            return new PythonDev();
        }else {
            return null;
        }
    }
}

测试

package com.aaa.dp.factory.simple;

/**
 * @FileName: Test
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 10:58
 * @Version: 1.0.0
 */
public class Test {

    public static void main(String[] args) {
        SoftwareTechnology softwareTechnology = AAAFactory.teachST(5);
        if(softwareTechnology!=null){
            softwareTechnology.studyST();
        }else {
            System.out.println("参数输入错误!");
        }

    }
}

缺点
1,违反开闭原则(增加新课程就需要修改工厂类)
2,代码耦合度高(任意一个课程出问题,可能影响其他课程的创建)

工厂方法模式
简介
为了解决简单工厂模式中存在的问题,定义一个工厂规范,生产产品不再是工厂完成,而是交给工厂的子类来完成,新增产品通过开分厂方式完成。可以降低产品之间的耦合度,完美遵循开闭原则。
实战
需求
假如AAA规模扩大,要添加新的课程,使用开分校的方式来增加课程!
代码
工厂标准

package com.aaa.dp.factory.method;

import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: AAAStanderd
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:24
 * @Version: 1.0.0
 */
public interface AAAStandered {

    /**
     * 教授软件类课程
     * @return
     */
    SoftwareTechnology testST();
}

新产品

package com.aaa.dp.factory.method;

import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: DotNetDev
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:27
 * @Version: 1.0.0
 */
public class DotNetDev implements SoftwareTechnology {
    @Override
    public void studyST() {
        System.out.println("头悬梁,锥刺股努力学习.net开发技术,高薪就业,将来当上CTO,迎娶白富美/高富帅......走上人生巅峰!");
    }
}
package com.aaa.dp.factory.method;

import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: UIDev
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:21
 * @Version: 1.0.0
 */
public class UIDev implements SoftwareTechnology {
    @Override
    public void studyST() {
        System.out.println("头悬梁,锥刺股努力学习UI开发技术,高薪就业,将来当上CTO,迎娶白富美/高富帅......走上人生巅峰!");
    }
}

分厂代码

package com.aaa.dp.factory.method;

import com.aaa.dp.factory.simple.AAAFactory;
import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: WuHanAAAFactory
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:26
 * @Version: 1.0.0
 */
public class WuHanAAAFactory  implements AAAStandered {
    @Override
    public SoftwareTechnology testST() {
        return new UIDev();
    }
}
package com.aaa.dp.factory.method;

import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: BeijingAAAFactory
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:27
 * @Version: 1.0.0
 */
public class BeijingAAAFactory  implements AAAStandered {
    @Override
    public SoftwareTechnology testST() {
         return new DotNetDev();
    }
}

测试

package com.aaa.dp.factory.method;

import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: Test
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:29
 * @Version: 1.0.0
 */
public class Test {
    public static void main(String[] args) {
        AAAStandered   wuHanAAAFactory =new WuHanAAAFactory();
        SoftwareTechnology softwareTechnology = wuHanAAAFactory.testST();
        softwareTechnology.studyST();
        AAAStandered   beijingAAAFactory =new BeijingAAAFactory();
        SoftwareTechnology softwareTechnology1 = beijingAAAFactory.testST();
        softwareTechnology1.studyST();
    }
}

缺点
代码复杂度变高

抽象工厂模式
简介
抽象工厂模式是方法工厂模式的增强版,在工厂方法模式中,只能提供生产一系列产品,而抽象工厂可以生产多个系列的产品。让不相关的产品系列拥有共同的父类或者接口,方便使用多态。
实战
需求
AAA规模不断扩大,不只在软件领域做培训,还在挖掘机领域做培训。。。
代码
抽象接口

package com.aaa.dp.factory.abstract1;

import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: AAAAbstractStandard
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:54
 * @Version: 1.0.0
 */
public interface AAAAbstractStandard {

    /**
     * 教授软件类课程
     * @return
     */
    SoftwareTechnology testST();

    /**
     * 教授挖掘机类课程
     * @return
     */
    DiggerTechnology testDT();


    //更多系列,可以再教授 美发   烹饪   汽修。。。
}

工厂类

package com.aaa.dp.factory.abstract1;

import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: ShenzhenAAAFactory
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:55
 * @Version: 1.0.0
 */
public class ShenzhenAAAFactory  implements  AAAAbstractStandard{
    @Override
    public SoftwareTechnology testST() {
        return new BigDataDev();
    }

    @Override
    public DiggerTechnology testDT() {
        return new SmallDiggerOpt();
    }
}

新增产品接口

package com.aaa.dp.factory.abstract1;

/**
 * @FileName: DiggerTechnology
 * @Description:  挖掘机技术接口
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:50
 * @Version: 1.0.0
 */
public interface DiggerTechnology {
    /**
     * 学习挖掘机课程的方法
     */
    void  studyDT();
}

产品实现类

package com.aaa.dp.factory.abstract1;

/**
 * @FileName: SmallDiggerOpt
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:52
 * @Version: 1.0.0
 */
public class SmallDiggerOpt  implements DiggerTechnology{
    @Override
    public void studyDT() {
        System.out.println("头悬梁,锥刺股努力学习小型挖掘机开发技术,高薪就业,将来当上CTO,迎娶白富美/高富帅......走上人生巅峰!");
    }
}
package com.aaa.dp.factory.abstract1;

/**
 * @FileName: SmallDiggerOpt
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:52
 * @Version: 1.0.0
 */
public class MediumDiggerOpt implements DiggerTechnology{
    @Override
    public void studyDT() {
        System.out.println("头悬梁,锥刺股努力学习中型挖掘机开发技术,高薪就业,将来当上CTO,迎娶白富美/高富帅......走上人生巅峰!");
    }
}

测试类

package com.aaa.dp.factory.abstract1;

import com.aaa.dp.factory.simple.SoftwareTechnology;

/**
 * @FileName: Test
 * @Description:
 * @Author: zhz
 * @CreateTime: 2024/11/27 11:58
 * @Version: 1.0.0
 */
public class Test {
    public static void main(String[] args) {
        ShenzhenAAAFactory shenzhenAAAFactory =new ShenzhenAAAFactory();
        SoftwareTechnology softwareTechnology = shenzhenAAAFactory.testST();
        softwareTechnology.studyST();
        DiggerTechnology diggerTechnology = shenzhenAAAFactory.testDT();
        diggerTechnology.studyDT();
    }
}

缺点
1,违反开闭原则(增加更多系列培训时,修改抽象接口)
2,耦合度高(多系列产品,相互影响)

单例模式
概念
单例模式是创建型模式之一,是一种常见的设计模式。就是在项目运行过程中一个类只存在一个对象,无论多少地方调用。
好处
节省内存
实现要点
1,私有构造(保证该类在其他地方无法实例化对象)
2,私有静态属性(私有,不能在其他地方调用。静态,伴随类加载执行,并且就执行一次)
3,公共的静态的返回当前实例方法
实现方式
懒汉非线程安全模式

package com.aaa.dp.singleton;

/**
 * @FileName: SingletonA
 * @Description: 懒汉非线程安全模式
 * @Author: zhz
 * @CreateTime: 2024/11/27 16:03
 * @Version: 1.0.0
 */
public class SingletonA {

    /**
     * 1,私有构造函数 (保证该类在其他地方无法实例化对象)
     */
     private SingletonA(){
     }

     //2,私有静态本类属性
     //私有:不能在其他地方调用。   静态:  伴随类加载执行,并且就执行一次
     private static  SingletonA singletonA = null;


    /**
     * 3,公共(其他地方可以调用)静态(通过类名称能调用)方法
     * @return
     */
     public static   SingletonA getInstance(){
         //判断为null  再实例化对象
         if(singletonA==null){
             singletonA =  new SingletonA();
         }
         return  singletonA;
     }



}

懒汉线程安全模式

package com.aaa.dp.singleton;

/**
 * @FileName: SingletonA
 * @Description: 懒汉线程安全模式
 * @Author: zhz
 * @CreateTime: 2024/11/27 16:03
 * @Version: 1.0.0
 */
public class SingletonB {

    /**
     * 1,私有构造函数 (保证该类在其他地方无法实例化对象)
     */
     private SingletonB(){
     }

     //2,私有静态本类属性
     //私有:不能在其他地方调用。   静态:  伴随类加载执行,并且就执行一次
     private static SingletonB singletonB = null;


    /**
     * 3,公共(其他地方可以调用)静态(通过类名称能调用)方法
     * @return
     */
     public static synchronized SingletonB getInstance(){
         //判断为null  再实例化对象
         if(singletonB==null){
             singletonB =  new SingletonB();
         }
         return  singletonB;
     }



}

懒汉双检锁模式

package com.aaa.dp.singleton;

/**
 * @FileName: SingletonA
 * @Description: 懒汉双检锁模式
 * @Author: zhz
 * @CreateTime: 2024/11/27 16:03
 * @Version: 1.0.0
 */
public class SingletonC {

    /**
     * 1,私有构造函数 (保证该类在其他地方无法实例化对象)
     */
     private SingletonC(){
     }

     //2,私有静态本类属性
     //私有:不能在其他地方调用。   静态:  伴随类加载执行,并且就执行一次
    /***
     * volatile   不稳定的,短暂的 java关键字
     *    1,多线程可见    (参考VolatileDemo类)volatile修改某一个属性时,一个线程如果更改了属性的值,另一个线程立马可见
     *    2,防止指令重排
     *
     *         在计算机底层,为了加快速度,在不影响程序执行结果的情况下,进行执行重排
     *         int i=1;
     *         int j=2;
     *         volatile int d=4;     a  b  赋值一定在 i  j之后执行
     *         int a=3;
     *         int b=4;
     *         int k=i+j;
     *         int c=a+b;
     *      SingletonC singletonC = new SingletonC()
     *       jvm分为三个步骤(不是原子性):
     *       1,先在堆开辟空间
     *       2,调用构造进行实例化
     *       3,拿引用singletonC指向开辟的空间
     *       执行顺序  不加volatile  可能  1 ->3 ->2   ...
     *                  加volatile  必然是1 2 3
     *
     */
     private static volatile SingletonC singletonC = null;


    /**
     * 3,公共(其他地方可以调用)静态(通过类名称能调用)方法
     * @return
     */
     public static  SingletonC getInstance(){
         //判断为null  再实例化对象
         if(singletonC==null){
             //使用代码块加锁
             synchronized (SingletonC.class) {
                 //再次判断
                 if(singletonC==null) {
                     singletonC = new SingletonC();
                 }
             }
         }
         return  singletonC;
     }



}

饿汉线程安全模式

package com.aaa.dp.singleton;

/**
 * @FileName: SingletonA
 * @Description: 饿汉线程安全
 * @Author: zhz
 * @CreateTime: 2024/11/27 16:03
 * @Version: 1.0.0
 */
public class SingletonD {

    /**
     * 1,私有构造函数 (保证该类在其他地方无法实例化对象)
     */
     private SingletonD(){
     }

     //2,私有静态本类属性
     private static  final SingletonD SINGLETON_D =
             new SingletonD();


    /**
     * 3,公共(其他地方可以调用)静态(通过类名称能调用)方法
     * @return
     */
     public static SingletonD getInstance(){
         return  SINGLETON_D;
     }



}

饿汉静态块模式

package com.aaa.dp.singleton;

/**
 * @FileName: SingletonA
 * @Description: 饿汉静态块线程安全
 * @Author: zhz
 * @CreateTime: 2024/11/27 16:03
 * @Version: 1.0.0
 */
public class SingletonE {

    /**
     * 1,私有构造函数 (保证该类在其他地方无法实例化对象)
     */
     private SingletonE(){
     }

     //2,私有静态本类属性
     private static   SingletonE SINGLETON_E = null;
       //静态匿名块
        static {
            //如果当前类创建不是一行代码,需要多行代码,使用该方式
             //参考mybatis第一章课程  SqlSessionFactory创建过程
             SINGLETON_E=new SingletonE();
        }


    /**
     * 3,公共(其他地方可以调用)静态(通过类名称能调用)方法
     * @return
     */
     public static SingletonE getInstance(){
         return  SINGLETON_E;
     }



}

懒汉和饿汉区别?
1,类加载速度:懒汉快(类加载时不实例化对象),饿汉慢
2,获取对象速度:懒汉慢(获取时需要实例化对象),饿汉快
3,生命周期:从早上8点启动tomcat到晚上8点停止tomcat,饿汉只要启动,就被实例化,生命周期就开始了。。从早8到晚8,饿汉什么时候调用,什么时候声明周期才开始。。。假如12调用,生命周期就是12点到晚8点。。。
volatile关键用法
volatile 不稳定的,短暂的 java关键字
1,多线程可见 (参考VolatileDemo类)volatile修改某一个属性时,一个线程如果更改了属性的值,另一个线程立马可见
2,防止指令重排

  •     在计算机底层,为了加快速度,在不影响程序执行结果的情况下,进行执行重排
    
    •     int i=1;
      
    •     int j=2;
      
    •     volatile int d=4;     a  b  赋值一定在 i  j之后执行
      
    •     int a=3;
      
    •     int b=4;
      
    •     int k=i+j;
      
    •     int c=a+b;
      
    •  SingletonC singletonC = new SingletonC()
      
    •   jvm分为三个步骤(不是原子性):
      
    •   1,先在堆开辟空间
      
    •   2,调用构造进行实例化
      
    •   3,拿引用singletonC指向开辟的空间
      
    •   执行顺序  不加volatile  可能  1 ->3 ->2   ...
      
    •              加volatile  必然是1 2 3
      

多线程可见实例

package com.aaa.dp.singleton;

/**
 * @FileName: VolatileDemo
 * @Description: Volatile 多线程可见的用法
 * @Author: zhz
 * @CreateTime: 2024/11/27 16:33
 * @Version: 1.0.0
 */
public class VolatileDemo extends  Thread{

    private static  volatile boolean flag = true;

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+",开始运行-----");
        //死循环,不会停止
        while (flag);
    }

    public static void main(String[] args) throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+",开始运行-----");
        new VolatileDemo().start();
        //main线程休眠5秒
        Thread.sleep(5000);
        System.out.println("5秒后让flag值变化");
        flag=false;
        System.out.println(Thread.currentThread().getName()+",结束运行-----");

        //不加 volatile  main线程把flag的值改为false   thread-0看不到它改了
        //加 volatile  main线程把flag的值改为false   thread-0直接看到它改了
    }
}

posted on 2024-12-29 17:23  小木不痞  阅读(28)  评论(0)    收藏  举报

导航