单例设计、多例设计、工厂设计模式、枚举的介绍及使用

简介: 单例设计、多例设计、工厂设计模式、枚举的介绍及使用

单例设计模式

单例设计模式宗旨:保证一个类只产生一个对象实例

实现单例模式的步骤:

  1. 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  2. 在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型的成员变量。
  3. 定义一个静态方法返回这个唯一对象。

饿汉式

无论是否有人使用本类对象,先把对象创建好了,供用户使用

public class Person {
    //1.私有空参数构造方法,不让用户直接创建对象
    private Person() { }

    //2.定义一个私有的静态的Person变量,并进行初始化赋值(创建一个对象给变量赋值)
    private static Person p = new Person();

    //3.定义一个公共的静态方法,返回Person对象
    public static Person getInstance(){
        return p;
    }
}


懒汉式

当使用对象的时候,才会创建对象;一直不使用对象是不会创建的。

public class Person {
    //1.私有空参数构造方法,不让用户直接创建对象
    private Person(){}

    //2.在类中定义一个私有的静态的Person变量,不进行初始化赋值
    private static Person p;

    //3.在类中定义一个公共的静态成员方法,返回Person对象,保证无论调用多少次方法,只返回一个对象。
    // 同时加synchronized锁解决多线程安全问题
    public static synchronized Person getInstance(){
        //增加一个判断,判断变量p是否为null(是null就是第一次调用方法,创建对象)
        if(p==null){
            p =  new Person();
        }
        //变量p不是null直接返回
        return p;
    }
}


多例设计模式

多例模式,是一种常用的软件设计模式。通过多例模式可以保证系统中,应用该模式的类有固定数量的实例。多例类要自我创建并管理自己的实例,还要向外界提供获取本类实例的方法。

例如:

  • 扑克牌程序,一个“扑克类”会创建固定的54个对象,不能多、也不能少。
  • 程序中需要用到“颜色的表示”,只能有三种颜色“红、绿、蓝”,一个“颜色类”应该只创建三个对象,来代 表这三个颜色。

多例模式的作用:多例模式可以保证系统中一个类有固定个数的实例,在实现需求的基础上, 能够提高实例的复用性.

实现多例模式的步骤:

  1. 创建一个类, 将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
  2. 在类中定义该类被创建的总数量
  3. 在类中定义存放类实例的list集合
  4. 在类中提供静态代码块,在静态代码块中创建类的实例
  5. 提供获取类实例的静态方法


获取多个通用的对象

import java.util.ArrayList;
import java.util.Random;

/*
    多例设计模式:获取多个通用的对象
    需求:只让程序产生3个Student对象,不能多,也不少
 */
public class Student {
    //1.私有空参数构造方法,不让用户直接创建对象
    private Student(){}

    //2.定义一个私有的,静态的,最终的变量,值定义创建对象的总个数
    private static final int MAX = 3;

    //3.定一个私有的,静态的ArrayList集合对象,用于存储多个对象
    private static ArrayList<Student> list = new ArrayList<>();

    //4.定义一个静态代码块(优先执行,只执行一次),创建3个对象,存储到集合中
    static {
        for (int i = 0; i < MAX; i++) {
            list.add(new Student());
        }
    }

    //5.定义一个公共的静态方法,给用户随机在集合中取出一个对象返回
    public static Student getInstance(){
        //定义一个Random对象
        Random r = new Random();
        //在集合索引范围内,产生一个随机数
        int index = r.nextInt(list.size());//[0,1,2]
        //通过随机索引,在集合中取出Student对象返回
        return list.get(index);
    }
}


获取多个特定的对象

/*
    多例设计模式:获取多个特定的的对象
    Sex类只产生两个Sex对象,一个代表男性别,一个代表女的性别
 */
@Data
public class Sex {
    //定义一个成员变量
    private String s;

    //1.私有数构造方法,不让用户直接创建对象
    private Sex(String s){
        this.s = s;
    }

    //2.定义两个固定的对象(公共,静态的,最终的)一个代表男性别,一个代表女的性别
    public static final Sex MAN = new Sex("男");
    public static final Sex WOMAN = new Sex("女");
}
@Data
public class Student {
    private String name;
    private int age;
    //定义性别使用Sex类型
    private Sex sex;
}
public class Demo01Multiton {
    public static void main(String[] args) {
        //创建Student对象
        Student s = new Student();
        //给成员变量赋值
        s.setName("张三");
        s.setAge(18);
        //s.setSex("abc");//性别的类型是Sex,不能随便给性别赋值,只能在Sex类中选择常量赋值
        //s.setSex(Sex.MAN);
        s.setSex(Sex.WOMAN);
        System.out.println(s);
    }
}


枚举

枚举的定义

枚举:就是"多例设计模式:获取多个特定的的对象"的一种简化写法

  • 枚举类在最前面罗列若干个枚举对象(都是常量)。(多例)
  • 枚举是不能在外部创建对象的,枚举的构造器默认是私有的。
  • 枚举通常用于做信息的标志和分类。

注意:枚举中没有添加构造方法,有默认空参数构造方法

/*
    需求:
        Sex类只产生两个Sex对象,一个代表男性别,一个代表女的性别
    使用多例实现:
        public static final Sex MAN = new Sex("男");
        public static final Sex WOMAN = new Sex("女");
    使用枚举实现:
        MAN 就相当于 public static final Sex MAN = new Sex();
        WOMAN 就相当于  public static final Sex WOMAN = new Sex();
    枚举中也可以定义成员变量,成员方法,构造方法(私有),这三个必须写在枚举常量的下边
        MAN("男") 就相当于 public static final Sex MAN = new Sex("男");
        WOMAN("女") 就相当于  public static final Sex WOMAN = new Sex("女");
 */
@AllArgsConstructor
@Getter
public enum Sex {
    
    //MAN, WOMAN //使用默认空参数构造方法创建两个对象
    
    MAN("男"),
    WOMAN("女");

    //定义成员变量
    private String s;

    //重写toSttring方法,返回对象中传递的字符串
    @Override
    public String toString() {
        return s;
    }
}


枚举中的自带方法

  • values() 方法

    将枚举类转换成一个枚举类型的数组

    枚举类中的元素是无法通过下标值来访问的,如果想指定访问枚举类中的某个值,只能直接写出它们的值,除此之外,别无他法。但是枚举类的 values() 方法可以将枚举类转换成一个枚举类型的数组,然后就可以通过数组下标来获取枚举类中的值

        @Test
        public void test(){
            TestEnum testEnum = TestEnum.values()[1];;
        }
  • ordinal() 方法

    用于获取当前枚举在定义时的索引, 从 0 开始依次累加

    当做一些状态存储时,可以使用状态的索引顺序来代表一个状态,例如 一个枚举中定义了 oneDay,twoDay,threedDay,使用 ordinal 获取时分别值为 0,1,2,即存储的 0,1,2 分别代表了上面的三个枚举。

        @Test
        public void test(){
            int ordinal = TestEnum.TEST1.ordinal();
        }


枚举的使用

@Data
public class Student {
    private String name;
    private int age;
    //定义性别,使用枚举类型的Sex
    private Sex sex;
}
public class Demo01Enum {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.setName("迪丽热巴");
        s1.setAge(18);
        s1.setSex(Sex.WOMAN);
        System.out.println(s1);

        Student s2 = new Student("马尔扎哈",28,Sex.MAN);
        System.out.println(s2);
    }
}


枚举的应用

枚举的作用:枚举通常可以用于做信息的分类,如性别,方向,季度等。

枚举表示性别:

public enum Sex {
    MAIL, FEMAIL;
}

枚举表示方向:

public enum Orientation {
    UP, RIGHT, DOWN, LEFT;
}

枚举表示季度

public enum Season {
    SPRING, SUMMER, AUTUMN, WINTER;
}


工厂设计模式

简单工厂设计模式

创建一个工厂类,在工厂类中定义一个生产对象的方法。要使用对象时不在自己创建对象了,而是使用工厂类的方法获取

好处:

  • 可以给工厂类的方法传递不同的动物名称,生产不同的动物对象
  • 解决类与类之间的耦合问题,增强了扩展性

弊端:

  • 胡乱传递一个动物名称,不存在,返回null,容易抛出空指针异常
  • 解决:可以使用工厂方法设计模式来来解决;创建多个工厂,每个工厂生产特定的动物
/*
    定义一个生产动物的工厂
    只能生产动物,不能生产其他的对象
    定义一个静态方法,根据用户传递的动物名称,创建指定的动物对象返回
 */
public class AnimalFactory {
    public static Animal getInstacne(String name){
        if("cat".equals(name)){
            return new Cat();
        }else if("dog".equals(name)){
            return new Dog();
        }else{
            //不是动物返回null
            return null;
        }
    }
}
public abstract class Animal {
    public abstract void eat();
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼!");
    }
}
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉!");
    }
}
public class Demo01SimpleFactory {
    public static void main(String[] args) {
        //使用工厂类AnimalFactory中的方法,获取指定的动物对象
        //获取Cat对象
        Animal cat = AnimalFactory.getInstacne("cat");
        cat.eat();

        //获取Dog对象
        Animal dog = AnimalFactory.getInstacne("dog");
        dog.eat();

        //胡乱传递一个动物名称
        Animal car = AnimalFactory.getInstacne("car");
        car.eat();//null.eat();  NullPointerException
    }
}


工厂方法设计模式(了解)

可以设计多个工厂,每个工厂生产不同的对象(猫工厂只生产猫,狗工厂只生产狗...)

好处:

  • 解决简单工厂设计模式的弊端,不让用户胡乱传递参数了
  • 什么工厂就生产什么动物

弊端:如果动物的种类过多,产生的工厂也会有很多个

/*
    定义一个工厂接口:所有的工厂都实现这个接口
 */
public interface Factory {
    //定义一个生产动物的抽象方法
    public abstract Animal getInstance();
}
/*
    生产猫的工厂,实现工厂接口,重写生产动物的方法
    只生产猫
 */
public class CatFactory implements Factory{
    @Override
    public Animal getInstance() {
        return new Cat();
    }
}
/*
    生产狗的工厂,实现工厂接口,重写生产动物的方法
    只生产狗
 */
public class DogFactory implements Factory{
    @Override
    public Animal getInstance() {
        return new Dog();
    }
}
public abstract class Animal {
    public abstract void eat();
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼!");
    }
}
public class Demo01FactoryMethod {
    public static void main(String[] args) {
        //创建生产猫的工厂==>生产猫
        CatFactory catFactory = new CatFactory();
        Animal cat = catFactory.getInstance();
        cat.eat();
        //猫工厂可以生产多个猫
        catFactory.getInstance().eat();
        catFactory.getInstance().eat();
        catFactory.getInstance().eat();
        catFactory.getInstance().eat();

        //创建生产狗的工厂==>生产狗
        DogFactory dogFactory = new DogFactory();
        Animal dog = dogFactory.getInstance();
        dog.eat();
        //狗工厂可以生产多个狗
        dogFactory.getInstance().eat();
        dogFactory.getInstance().eat();
        dogFactory.getInstance().eat();
        dogFactory.getInstance().eat();
        dogFactory.getInstance().eat();
    }
}
相关文章
|
2月前
|
设计模式 安全 测试技术
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
【C/C++ 设计模式 单例】单例模式的选择策略:何时使用,何时避免
62 0
|
2月前
|
设计模式 缓存 安全
单例设计模式的优缺点
单例设计模式的优缺点
32 0
|
2月前
|
设计模式 XML 存储
关于 ABAP 单例设计模式的一个冷门知识点
关于 ABAP 单例设计模式的一个冷门知识点
23 0
|
2月前
|
设计模式 安全 Java
【设计模式】2、设计模式分类和单例设计模式
【设计模式】2、设计模式分类和单例设计模式
26 0
|
2月前
|
设计模式 Java
26、Java 简单实现单例设计模式(饿汉式和懒汉式)
26、Java 简单实现单例设计模式(饿汉式和懒汉式)
30 2
|
2月前
|
设计模式 安全 Java
在Java中即指单例设计模式
在Java中即指单例设计模式
21 0
|
4天前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
|
4月前
|
设计模式 缓存 安全
Go语言必学的单例设计模式
Go语言必学的单例设计模式
35 0
|
4月前
|
设计模式 存储 Java
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(四)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(四)
93 1
|
4月前
|
设计模式 存储 安全
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(三)
多线程编程设计模式(单例,阻塞队列,定时器,线程池)(三)
38 2