设计模式:02-单例模式 / 简单工厂模式 / 工厂方法模式 / 抽象工厂模式

本篇博客主要是学习 韩顺平_Java设计模式 做一个学习笔记使用

1. 单例模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法(静态方法)。 比如 Hibernate 的 SessionFactory,它充当数据存储源的代理,并负责创建 Session 对象。SessionFactory 并不是 轻量级的,一般情况下,一个项目通常只需要一个 SessionFactory 就够,这是就会使用到单例模式。

1.1步骤

  1. 构造器私有化 ( 防止 new )
  2. 类的内部创建对象
  3. 向外暴露一个静态的公共方法。getInstance
  4. 代码实现

说明:
单例模式的实现由很多种写法, 其中主要有分类: 饿汉, 懒汉
在这里我就不写那些比较普通的, 或者线程不安全的写法了, 直接写出几种比较推荐的写法好了

1.2代码

/**
 * 单例模式
 * @author houyu
 * @createTime 2019/11/8 9:40
 */
public class SingletonObject {

    /** 私有构造 */
    private SingletonObject() {}

    /** -------------------- 方式1 (推荐 JVM 保证) -------------------- */
    private static class SingletonHolder {
        private static final SingletonObject instance = new SingletonObject();
    }

    public static SingletonObject getInstance() {
        return SingletonHolder.instance;
    }
    /*
     * 分析:
     * 使用内部类的形式, 就算主类 (SingletonObject) 加载了, 内部类( SingletonHolder )也是使用到的时候再加载的, 由于使用了 private 修饰了, 其他类无法使用
     *
     * SingletonObject 导致类加载的原因有很多, 其中有一种可能就是被其他列 import 也会导致类的加载, 但是在不调用 getInstance 的使用, 都没有创建实例
     */


    /** -------------------- 方式1 (推荐 JVM 保证) -------------------- */

    /** -------------------- 方式2 (次推荐 饿汉形式 JVM 保证) -------------------- */
    private static final SingletonObject instance = new SingletonObject();

    public static SingletonObject getInstance2() {
        return instance;
    }
    /*
     * 分析:
     * 使用静态常量的形式 也就是类一加载就创建实例, 一定程度上会导致内存的浪费(如果程序启动到结束都没有使用到改用的时候)
     * 但是阅读jdk源码, 发现很多都是使用这个简单的形式创建的单例模式,因此 也是很受欢迎的
     */

    /** -------------------- 方式3 (次推荐 synchronized volatile 锁机制保证, 双重检查) -------------------- */
    private static volatile SingletonObject instance3;

    public static SingletonObject getInstance3() {
        if(instance3 == null) {
            synchronized(Object.class) {
                // if(instance3 == null) {
                //     instance3 = new SingletonObject();
                // }
                instance3 = instance3 == null ? new SingletonObject() : instance3;
            }
        }
        return instance3;
    }
    /*
     * 分析:
     * 使用 synchronized volatile 锁机制保证 加载双重检测, 实现实例只会创建一次
     */

    /** -------------------- 方式4 (推荐 JVM 保证) -------------------- */
    public enum SingletonEnumObject {
        /**  */
        INSTANCE;

        public void testMethod() {
            System.out.println("------testMethod()-----");
        }

        public static void main(String[] args) {
            SingletonEnumObject.INSTANCE.testMethod();
        }
    }

    /* 或者使用下面的方式 */

    public enum SingletonEnum {
        /***/
        INSTANCE(new SingletonObject());
        /***/
        private SingletonObject singletonObject;
        SingletonEnum(SingletonObject singletonObject) {
            this.singletonObject = singletonObject;
        }
    }

    public static SingletonObject getInstance4() {
        return SingletonEnum.INSTANCE.singletonObject;
    }

    /*
     * 分析:
     * 使用枚举创建的单例模式:也是比较推荐的, 其实底层也是静态内部类的形式
     */

}

2. 工厂模式-简单工厂模式(静态工厂模式)

基本介绍

  1. 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品 类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
  2. 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
  3. 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式.

代码

import java.util.Scanner;

/**
 * 简单工厂模式也叫静态工厂模式,
 * 因为也可以写成静态的形式如果不写成静态, 那就需要使用 依赖 ,组合 等形式进行关联
 *
 * 简单介绍:
 * 定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
 *
 *  @author houyu
 * @createTime 2019/11/16 14:48
 */
public class SimpleFactory {


    /**
     * 披萨
     */
    public static class Pizza {

        String name;

        public void prepare() {
            System.out.println(this.name + ": 准备阶段");
        }
        public void bake() {
            System.out.println(this.name + ": 烘烤阶段");
        }
        public void cut() {
            System.out.println(this.name + ": 切割阶段");
        }
        public void bax() {
            System.out.println(this.name + ": 包装阶段");
        }
    }

    /**
     * 奶酪披萨
     */
    public static class CheesePizza extends Pizza {
        public CheesePizza() {
            super.name = "奶酪披萨";
        }
    }

    /**
     * 希腊披萨
     */
    public static class GreekPizza extends Pizza {
        public GreekPizza() {
            super.name = "希腊披萨";
        }
    }

    /**
     * 由 SimpleFactory 的 createPizza 创建披萨
     * @param type 披萨类型
     * @return  披萨实例对象
     */
    public static Pizza createPizza(String type) {
        switch(type) {
            case "cheese":
                return new CheesePizza();
            case "greek":
                return new GreekPizza();
            default:
                return null;
        }
    }

    public static void main(String[] args) {

        do {
            System.out.print("请输入披萨类型:");
            Scanner scanner = new Scanner(System.in);
            String type = scanner.nextLine();
            Pizza pizza = SimpleFactory.createPizza(type);
            if(pizza == null) {
                System.out.println("创建披萨失败");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.bax();

        } while(true);
        /**
         * 控制台:
         *
         * 请输入披萨类型:cheese
         * 奶酪披萨: 准备阶段
         * 奶酪披萨: 烘烤阶段
         * 奶酪披萨: 切割阶段
         * 奶酪披萨: 包装阶段
         * 请输入披萨类型:greek
         * 希腊披萨: 准备阶段
         * 希腊披萨: 烘烤阶段
         * 希腊披萨: 切割阶段
         * 希腊披萨: 包装阶段
         * 请输入披萨类型:123
         * 创建披萨失败
         */
    }

}

2.1 工厂模式在 JDK-Calendar 应用的源码分析

// 1.0 
Calendar cal = Calendar.getInstance();

// 2.0 
public static Calendar getInstance()
{
   Locale aLocale = Locale.getDefault(Locale.Category.FORMAT);
   return createCalendar(defaultTimeZone(aLocale), aLocale);
}

// 3.0
private static Calendar createCalendar(TimeZone zone,
                                   Locale aLocale)
{
    CalendarProvider provider =
        LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                             .getCalendarProvider();
    if (provider != null) {
        try {
            return provider.getInstance(zone, aLocale);
        } catch (IllegalArgumentException iae) {
            // fall back to the default instantiation
        }
    }

    Calendar cal = null;

    if (aLocale.hasExtensions()) {
        String caltype = aLocale.getUnicodeLocaleType("ca");
        if (caltype != null) {
            switch (caltype) {
            case "buddhist":
            cal = new BuddhistCalendar(zone, aLocale);
                break;
            case "japanese":
                cal = new JapaneseImperialCalendar(zone, aLocale);
                break;
            case "gregory":
                cal = new GregorianCalendar(zone, aLocale);
                break;
            }
        }
    }
    if (cal == null) {
        // If no known calendar type is explicitly specified,
        // perform the traditional way to create a Calendar:
        // create a BuddhistCalendar for th_TH locale,
        // a JapaneseImperialCalendar for ja_JP_JP locale, or
        // a GregorianCalendar for any other locales.
        // NOTE: The language, country and variant strings are interned.
        if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
            cal = new BuddhistCalendar(zone, aLocale);
        } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                   && aLocale.getCountry() == "JP") {
            cal = new JapaneseImperialCalendar(zone, aLocale);
        } else {
            cal = new GregorianCalendar(zone, aLocale);
        }
    }
    return cal;
}

2.2 使用enum优化 switch 或者 if

public class Test {

    public static void main(String[] args) {
        String type = "Student";
        Penson person = PersonEnum.valueOf(type).getPerson();
        System.out.println("person.toString() = " + person.toString());
    }

}

abstract class Penson {

}

class Student extends Penson {
    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder("Student{");
        builder.append('}');
        return builder.toString();
    }
}

class Teacher extends Penson {
    @Override
    public String toString() {
        final StringBuilder builder = new StringBuilder("Teacher{");
        builder.append('}');
        return builder.toString();
    }
}

enum PersonEnum {
    //
    Student(new Student()),
    Teacher(new Teacher());

    private Penson person;

    PersonEnum(Penson person) {
        this.person = person;
    }

    public Penson getPerson() {
        return person;
    }
}

3. 工厂模式-工厂方法模式

工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例 化推迟到子类。

代码实现

import java.util.Scanner;

/**
 * 工厂方法模式:
 * 定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例 化推迟到子类。
 *
 *  @author houyu
 * @createTime 2019/11/16 14:48
 */
public abstract class FactoryMethod {

    /**
     * 披萨
     */
    public static class Pizza {

        String name;

        public void prepare() {
            System.out.println(this.name + ": 准备阶段");
        }

        public void bake() {
            System.out.println(this.name + ": 烘烤阶段");
        }

        public void cut() {
            System.out.println(this.name + ": 切割阶段");
        }

        public void bax() {
            System.out.println(this.name + ": 包装阶段");
        }
    }

    /**
     * 北京奶酪披萨
     */
    public static class BJCheesePizza extends Pizza {

        public BJCheesePizza() {
            super.name = "北京奶酪披萨";
        }
    }

    /**
     * 北京希腊披萨
     */
    public static class BJGreekPizza extends Pizza {

        public BJGreekPizza() {
            super.name = "北京希腊披萨";
        }
    }

    /**
     * 伦敦奶酪披萨
     */
    public static class LDCheesePizza extends Pizza {

        public LDCheesePizza() {
            super.name = "伦敦奶酪披萨";
        }
    }

    /**
     * 伦敦希腊披萨
     */
    public static class LDGreekPizza extends Pizza {

        public LDGreekPizza() {
            super.name = "伦敦希腊披萨";
        }
    }

    /**
     *  定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例 化推迟到子类。
     * @param type 披萨类型
     * @return 披萨实例对象
     */
    public abstract Pizza createPizza(String type);

    /**
     * 北京工厂
     */
    public static class BJFactoryMethod extends FactoryMethod {
        @Override
        public Pizza createPizza(String type) {
            switch(type) {
                case "cheese":
                    return new BJCheesePizza();
                case "greek":
                    return new BJGreekPizza();
                default:
                    return null;
            }
        }
    }

    /**
     * 伦敦工厂
     */
    public static class LDFactoryMethod extends FactoryMethod {
        @Override
        public Pizza createPizza(String type) {
            switch(type) {
                case "cheese":
                    return new LDCheesePizza();
                case "greek":
                    return new LDGreekPizza();
                default:
                    return null;
            }
        }
    }

    public static void main(String[] args) {
        do {

            System.out.print("请输入地区:");
            Scanner scanner = new Scanner(System.in);
            String area = scanner.nextLine();
            System.out.print("请输入披萨类型:");
            String type = scanner.nextLine();
            Pizza pizza = null;
            if(area.equals("bj")) {
                pizza = new BJFactoryMethod().createPizza(type);
            } else if(area.equals("ld")) {
                pizza = new LDFactoryMethod().createPizza(type);
            }
            if(pizza == null) {
                System.out.println("创建披萨失败");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.bax();

        } while(true);
        /*
         * 控制台:
         * 
         * 请输入地区:bj
         * 请输入披萨类型:cheese
         * 北京奶酪披萨: 准备阶段
         * 北京奶酪披萨: 烘烤阶段
         * 北京奶酪披萨: 切割阶段
         * 北京奶酪披萨: 包装阶段
         * 请输入地区:ld
         * 请输入披萨类型:greek
         * 伦敦希腊披萨: 准备阶段
         * 伦敦希腊披萨: 烘烤阶段
         * 伦敦希腊披萨: 切割阶段
         * 伦敦希腊披萨: 包装阶段
         * 请输入地区:xx
         * 请输入披萨类型:xx
         * 创建披萨失败
         *
         */
    }

}

4. 工厂模式-抽象工厂模式

基本介绍

  1. 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
  2. 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
  3. 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
  4. 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应 的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。

代码

import java.util.Scanner;

/**
 * @author houyu
 * @createTime 2019/11/16 16:29
 */
public class AbstractFactory {

    /**
     * 披萨
     */
    public static class Pizza {

        String name;

        public void prepare() {
            System.out.println(this.name + ": 准备阶段");
        }

        public void bake() {
            System.out.println(this.name + ": 烘烤阶段");
        }

        public void cut() {
            System.out.println(this.name + ": 切割阶段");
        }

        public void bax() {
            System.out.println(this.name + ": 包装阶段");
        }
    }

    /**
     * 北京奶酪披萨
     */
    public static class BJCheesePizza extends Pizza {

        public BJCheesePizza() {
            super.name = "北京奶酪披萨";
        }
    }

    /**
     * 北京希腊披萨
     */
    public static class BJGreekPizza extends Pizza {

        public BJGreekPizza() {
            super.name = "北京希腊披萨";
        }
    }

    /**
     * 伦敦奶酪披萨
     */
    public static class LDCheesePizza extends Pizza {

        public LDCheesePizza() {
            super.name = "伦敦奶酪披萨";
        }
    }

    /**
     * 伦敦希腊披萨
     */
    public static class LDGreekPizza extends Pizza {

        public LDGreekPizza() {
            super.name = "伦敦希腊披萨";
        }
    }

    /**
     * 抽象工厂
     */
    public interface BaseFactory {

        /**
         * 由实现子类具体实现
         * @param type
         */
        Pizza createPizza(String type);
    }

    /**
     * 北京工厂
     */
    public static class BJFactory implements BaseFactory {

        @Override
        public Pizza createPizza(String type) {
            switch(type) {
                case "cheese":
                    return new BJCheesePizza();
                case "greek":
                    return new BJGreekPizza();
                default:
                    return null;
            }
        }
    }

    /**
     * 伦敦工厂
     */
    public static class LDFactory implements BaseFactory {

        @Override
        public Pizza createPizza(String type) {
            switch(type) {
                case "cheese":
                    return new LDCheesePizza();
                case "greek":
                    return new LDGreekPizza();
                default:
                    return null;
            }
        }
    }

    public static void main(String[] args) {
        do {

            System.out.print("请输入地区:");
            Scanner scanner = new Scanner(System.in);
            String area = scanner.nextLine();
            System.out.print("请输入披萨类型:");
            String type = scanner.nextLine();
            BaseFactory factory = null;
            if(area.equals("bj")) {
                factory = new BJFactory();
            } else if(area.equals("ld")) {
                factory = new LDFactory();
            }
            if(factory == null) {
                System.out.println("创建披萨失败: 找不到工厂");
                break;
            }
            Pizza pizza = factory.createPizza(type);
            if(pizza == null) {
                System.out.println("创建披萨失败: 找不到工厂");
                break;
            }
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.bax();

        } while(true);
        /*
         * 请输入地区:bj
         * 请输入披萨类型:cheese
         * 北京奶酪披萨: 准备阶段
         * 北京奶酪披萨: 烘烤阶段
         * 北京奶酪披萨: 切割阶段
         * 北京奶酪披萨: 包装阶段
         * 请输入地区:ld
         * 请输入披萨类型:greek
         * 伦敦希腊披萨: 准备阶段
         * 伦敦希腊披萨: 烘烤阶段
         * 伦敦希腊披萨: 切割阶段
         * 伦敦希腊披萨: 包装阶段
         * 请输入地区:xx
         * 请输入披萨类型:xx
         * 创建披萨失败: 找不到工厂
         */

    }
}

发布了46 篇原创文章 · 获赞 13 · 访问量 2万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览