创建型模式是关注于如何高效率的创建对象,将对象创建和对象使用的过程分离,避免了代码中大量对象实例化的操作,使的代码高内聚低耦合

单例模式

简要意思:确保一个类只有一个实例,并提供一个全局访问点。

适用场景:在一个系统中有需要控制数量的实例对象,每次访问都需要访问相同的实例对象。

例子:在英雄联盟里一局游戏里十名玩家所看到的大龙小龙刷新时间是相同的,那么获取大龙刷新时间的大龙刷新状态管理器再一局游戏里必须是单例对象。来保障大龙资源的唯一性和一致性。

饿汉式和饱汉式

简要意思:饿汉式为在使用对象之前就创建好对象,饱汉式为使用对象的时候再进行创建对象的操作

饿汉式

public class BaronManager {
    // 1. 私有化静态实例,类加载时就会创建
    private static final BaronManager instance = new BaronManager();

    // 2. 私有化构造方法,防止外部创建对象
    private BaronManager() {
        // 构造函数也可以执行一些初始化操作
    }

    // 3. 提供公共的静态方法获取唯一实例
    public static BaronManager getInstance() {
        return instance;
    }

    // 示例方法,表示击杀大龙
    public void killBaron() {
        System.out.println("Baron Nashor has been slain!");
    }

    // 示例方法,表示大龙重生
    public void respawnBaron() {
        System.out.println("Baron Nashor has respawned!");
    }
}

我们来测试一下

public class Test {
    public static void main(String[] args) {
        BaronManager instance1 = BaronManager.getInstance();
        BaronManager instance2 = BaronManager.getInstance();
        System.out.println(instance2==instance1);
    }
}

结果为

饱汉式

public class BaronManager {
    // 1. 私有化构造方法,防止外部创建对象
    private BaronManager() {
        // 构造方法可以包含一些初始化逻辑
    }

    // 2. 静态内部类,用来持有单例实例
    private static class SingletonHelper {
        // 静态内部类中声明并初始化单例对象
        private static final BaronManager INSTANCE = new BaronManager();
    }

    // 3. 提供公共静态方法获取单例实例
    public static BaronManager getInstance() {
        return SingletonHelper.INSTANCE; // 只有在首次调用时才会创建实例
    }

    // 示例方法,表示击杀大龙
    public void killBaron() {
        System.out.println("Baron Nashor has been slain!");
    }

    // 示例方法,表示大龙重生
    public void respawnBaron() {
        System.out.println("Baron Nashor has respawned!");
    }
}

可能很多人会问为什么饱汉式需要用到静态内部类来创建呢,是因为我们为了保障BaronManager的唯一性,我们必须注意线程安全问题。我们利用了类加载机制(java类加载机制为懒加载并且只加载一次,所以线程是安全的)静态内部类机制(静态内部类只有被调用的时候才会加载而且只会调用一次)

工厂模式

简要意思:帮助我们实例化不同的对象,它通过定义一个接口或抽象类,允许子类实现该接口,从而在运行时决定实例化哪种具体类。

适用场景:需要创建的对象都是继承同一父类时,或者为了满足单一职责链式,将对象的创建和使用分开解耦合

例子:在《英雄联盟》中,工厂模式可以用于创建不同类型的英雄技能。每个英雄都有自己的特性和技能,但它们通常都实现了一个共同的接口。这种情况下,工厂模式非常适合用于管理英雄的创建过程。

简单工厂

简单工厂:客户端传入参数,又简单工厂类创建对象,但是违反开闭原则,新增产品时需要修改简单工厂类。

结构:简单工厂,抽象产品,具体产品

// 英雄接口
interface Champion {
    void useAbility();
}

// 具体英雄:法师
class Lux implements Champion {
    @Override
    public void useAbility() {
        System.out.println("拉克丝施放光之束缚!");
    }
}

// 具体英雄:刺客
class Zed implements Champion {
    @Override
    public void useAbility() {
        System.out.println("劫使用飞镖!");
    }
}

// 具体英雄:战士
class Garen implements Champion {
    @Override
    public void useAbility() {
        System.out.println("盖伦使用审判!");
    }
}

// 简单工厂
class ChampionFactory {
    public static Champion createChampion(String type) {
        switch (type) {
            case "法师":
                return new Lux();
            case "刺客":
                return new Zed();
            case "战士":
                return new Garen();
            default:
                throw new IllegalArgumentException("未知英雄类型");
        }
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Champion lux = ChampionFactory.createChampion("法师");
        lux.useAbility();  // 输出: 拉克丝施放光之束缚!

        Champion zed = ChampionFactory.createChampion("刺客");
        zed.useAbility();  // 输出: 劫使用飞镖!

        Champion garen = ChampionFactory.createChampion("战士");
        garen.useAbility();  // 输出: 盖伦使用审判!
    }
}

工厂方法

工厂方法:定义抽象接口,工厂和产品实现接口,新增的产品只需要实现接口,但是会造成类爆炸。

结构:抽象产品,具体产品,抽象工厂,具体工厂

// 英雄接口
interface Champion {
    void useAbility();
}

// 具体英雄:法师
class Lux implements Champion {
    @Override
    public void useAbility() {
        System.out.println("拉克丝施放光之束缚!");
    }
}

// 具体英雄:刺客
class Zed implements Champion {
    @Override
    public void useAbility() {
        System.out.println("劫使用飞镖!");
    }
}

// 具体英雄:战士
class Garen implements Champion {
    @Override
    public void useAbility() {
        System.out.println("盖伦使用审判!");
    }
}

// 英雄工厂接口
interface ChampionFactory {
    Champion createChampion();
}

// 具体法师工厂
class LuxFactory implements ChampionFactory {
    @Override
    public Champion createChampion() {
        return new Lux();
    }
}

// 具体刺客工厂
class ZedFactory implements ChampionFactory {
    @Override
    public Champion createChampion() {
        return new Zed();
    }
}

// 具体战士工厂
class GarenFactory implements ChampionFactory {
    @Override
    public Champion createChampion() {
        return new Garen();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        ChampionFactory luxFactory = new LuxFactory();
        Champion lux = luxFactory.createChampion();
        lux.useAbility();  // 输出: 拉克丝施放光之束缚!

        ChampionFactory zedFactory = new ZedFactory();
        Champion zed = zedFactory.createChampion();
        zed.useAbility();  // 输出: 劫使用飞镖!

        ChampionFactory garenFactory = new GarenFactory();
        Champion garen = garenFactory.createChampion();
        garen.useAbility();  // 输出: 盖伦使用审判!
    }
}

抽象工厂

提供一个接口用于创建一系列相关或依赖的对象,而无需指定它们具体的类。它允许客户端代码与具体产品解耦,提高了代码的灵活性和可扩展性。

就是有两种类似

结构:产品接口,具体产品,抽象工厂接口,具体工厂

// 英雄接口
interface Champion {
    void useAbility();
}

// 斗士接口
interface Fighter extends Champion {
}

// 决斗大师接口
interface Duelist extends Champion {
}

// 艾欧尼亚的斗士
class Shen implements Fighter {
    @Override
    public void useAbility() {
        System.out.println("慎使用影之突袭!");
    }
}

// 艾欧尼亚的决斗大师
class Yi implements Duelist {
    @Override
    public void useAbility() {
        System.out.println("易大师使用阿尔法突袭!");
    }
}

// 诺克萨斯的斗士
class Darius implements Fighter {
    @Override
    public void useAbility() {
        System.out.println("德莱厄斯使用诺克萨斯之手!");
    }
}

// 诺克萨斯的决斗大师
class Riven implements Duelist {
    @Override
    public void useAbility() {
        System.out.println("瑞文使用破碎之剑!");
    }
}

// 抽象工厂接口
interface ChampionFactory {
    Fighter createFighter();
    Duelist createDuelist();
}

// 艾欧尼亚工厂
class IoniaFactory implements ChampionFactory {
    @Override
    public Fighter createFighter() {
        return new Shen();
    }

    @Override
    public Duelist createDuelist() {
        return new Yi();
    }
}

// 诺克萨斯工厂
class NoxusFactory implements ChampionFactory {
    @Override
    public Fighter createFighter() {
        return new Darius();
    }

    @Override
    public Duelist createDuelist() {
        return new Riven();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        ChampionFactory ioniaFactory = new IoniaFactory();
        Fighter ioniaFighter = ioniaFactory.createFighter();
        Duelist ioniaDuelist = ioniaFactory.createDuelist();

        ioniaFighter.useAbility();  // 输出: 慎使用影之突袭!
        ioniaDuelist.useAbility();   // 输出: 易大师使用阿尔法突袭!

        ChampionFactory noxusFactory = new NoxusFactory();
        Fighter noxusFighter = noxusFactory.createFighter();
        Duelist noxusDuelist = noxusFactory.createDuelist();

        noxusFighter.useAbility();   // 输出: 德莱厄斯使用诺克萨斯之手!
        noxusDuelist.useAbility();    // 输出: 瑞文使用破碎之剑!
    }
}

原型模式

原型模式是一种创建型设计模式,它允许通过复制已有的对象来创建新对象,而不是通过构造函数来实例化。原型模式通常用于需要大量相似对象的场景,可以提高性能并简化对象的创建过程。

  • 克隆:通过实现一个克隆方法(通常是 clone()),可以创建对象的副本。这个方法在对象本身内部定义,而不是在外部创建。

  • 避免重复初始化:当一个对象的初始化成本较高时,可以通过复制现有对象来节省时间和资源。

  • 灵活性:允许在运行时动态地创建对象,可以使用不同的配置来生成新对象。

比如说英雄联盟里面小丑的大招克隆一个和当前对象一模一样状态的实例,而不是重新创建

我们又需要引出一个知识点就是深拷贝和浅拷贝

浅拷贝

  • 定义:浅拷贝创建一个新对象,并将原对象的字段值复制到新对象中。如果字段是基本类型(如整型、字符等),则复制其值;如果字段是引用类型(如对象),则复制引用,而不是对象本身。

  • 影响:对新对象中引用类型字段的修改可能会影响到原对象,因为它们指向同一个内存地址。

深拷贝

  • 定义:深拷贝不仅创建一个新对象,还复制对象中的所有字段,包括引用类型的对象,确保新对象和原对象之间完全独立。

  • 影响:对新对象中任何字段的修改不会影响原对象,因为所有的对象都在内存中是独立的。

// 原型接口
interface Clonable {
    Clonable clone();
}

// 具体原型类:小丑
class Jester implements Clonable {
    private String name;

    public Jester(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public Clonable clone() {
        return new Jester(this.name);
    }

    public void ultimate() {
        System.out.println(name + " 使用终极表演,制造幻象!");
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 创建小丑对象
        Jester originalJester = new Jester("小丑");

        // 小丑使用大招,克隆自己
        Jester clonedJester = (Jester) originalJester.clone();

        // 小丑和幻象同时进行技能
        originalJester.ultimate();  // 输出: 小丑 使用终极表演,制造幻象!
        clonedJester.ultimate();     // 输出: 小丑 使用终极表演,制造幻象!
    }
}

建造者模式

建造者模式(Builder Pattern)是一种创建型设计模式,它允许通过分步骤的方式创建复杂对象。与直接使用构造函数不同,建造者模式提供了更清晰的对象构建过程,能够逐步配置对象的各个部分。

主要特点:

  1. 分离复杂对象的构建与表示:建造者模式将复杂对象的创建过程和表示解耦,使得同样的构建过程可以创建不同的表示。

  2. 步骤灵活性:可以按需选择和组合构建的步骤,适合需要多种配置的对象。

  3. 可读性:通过使用流式接口(method chaining),使代码更具可读性和可维护性。

适用场景:

  • 当构造对象的过程复杂时。

  • 当需要创建的对象可能有不同的表示或状态时。

  • 当对象的构建过程需要多步骤,且顺序可变时。

// 具体对象类:英雄
class Champion {
    private String name;
    private int health;
    private int attackDamage;
    private String role;

    // 私有构造函数
    private Champion(Builder builder) {
        this.name = builder.name;
        this.health = builder.health;
        this.attackDamage = builder.attackDamage;
        this.role = builder.role;
    }

    public static class Builder {
        private String name; // 必需参数
        private int health = 100; // 默认值
        private int attackDamage = 10; // 默认值
        private String role; // 角色可以选择

        public Builder(String name) {
            this.name = name;
        }

        public Builder setHealth(int health) {
            this.health = health;
            return this;
        }

        public Builder setAttackDamage(int attackDamage) {
            this.attackDamage = attackDamage;
            return this;
        }

        public Builder setRole(String role) {
            this.role = role;
            return this;
        }

        public Champion build() {
            return new Champion(this);
        }
    }

    @Override
    public String toString() {
        return "Champion{" +
                "name='" + name + '\'' +
                ", health=" + health +
                ", attackDamage=" + attackDamage +
                ", role='" + role + '\'' +
                '}';
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Champion yasuo = new Champion.Builder("亚索")
                .setHealth(200)
                .setAttackDamage(60)
                .setRole("战士")
                .build();

        Champion jinx = new Champion.Builder("金克丝")
                .setHealth(180)
                .setAttackDamage(70)
                .setRole("射手")
                .build();

        System.out.println(yasuo);  // 输出: Champion{name='亚索', health=200, attackDamage=60, role='战士'}
        System.out.println(jinx);    // 输出: Champion{name='金克丝', health=180, attackDamage=70, role='射手'}
    }
}