03_Spring_Bean专题

在说Bean之前,我们先对工厂模式有个简单的认识,把这一部分的知识做一个铺垫。后面我们说到Spring Bean的管理会用来到这个模式。

一、工厂模式

工厂模式是一种设计模式,那设计模式又是什么呢?

简单来说,设计模式,它是一种可以被重复利用的解决方案。1995年《设计模式》由由Erich Gamma,Richard Helm,Ralph Johnson和John Vlissides合著,这四位作者被称为“四人组”(GoF,Gang of Four)。

在书中描述了23种设计模式,因为“四人组”当时出书时间比较早,如果到现在来说应该还会有一些书中没有纳入的新的设计模式。当我们平时说的设计模式就是指的这23种设计模式了。

GoF23种设计模式又可以分为三大类:

1、解决对象创建问题的(创建型),有5个

单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式

2、一些数或者是对象组装在一起的经典结构(结构型),有7个

代理模式、装饰模式、适配器模式、组合模式、享元模式、外观模式、桥接模式

3、解类或者是对象之前交互问题(行为型)

策略模式、模式方法模式、观察者模式、责任链模式、迭代子模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

现在我们要说的是工厂模式,它是用来解决创建问题的,我们的Bean产生不就是要重点解决谁帮我们创建对象,谁帮我们维护各个对象之间的关系吗?所以Spring底层使用了大量的工厂模式。

工厂模式的三种形态

  • 简单工厂模式:它不属于23种设计模式之一。简单工厂模式又叫静态工厂方法模式,它是工厂方法模式的一种特殊实现
  • 工厂方法模式
  • 抽象工厂模式

接下来我们对这三种形态做进一步的了解

简单工厂模式

对于简单工厂模式来说,它分为三个角色:抽象产品角色、具体产品角色、工厂类角色

下面我们用实际的代码来说明

抽象产品角色,它是对具体的各个产品的行为特征的抽象,它是不能产生具体的对象(或者说产品的)

/**
 * 抽象产品角色
 */
public abstract class Weapon {

    /**
     * 所有武器都有攻击的行为
     */
    public abstract void attack();
}

具体产品角色,它就是实实在在在描最终要生产的对象/产品,一般来说具体产品角色是会有多个的,下面有三个类,它们都是具象化的具体产品描述。

/**
 * 具体产品角色
 */
public class Tank extends Weapon {
    @Override
    public void attack() {
        System.out.println("坦克开炮~");
    }
}


/**
 * 具体产品角色
 */
public class Fighter extends Weapon {
    @Override
    public void attack() {
        System.out.println("战斗机投下导弹~");
    }
}


/**
 * 具体产品角色
 */
public class Dagger extends Weapon {
    @Override
    public void attack() {
        System.out.println("匕首攻击~");
    }
}

工厂类角色,这个角色就是具体来为我们提供对象的,工厂嘛肯定是生产产品的地方

/**
 * 工厂类角色
 */
public class WeaponFactory {
    /**
     * 根据不同的武器类型,返回不同的武器对象
     * @param weaponType
     * @return
     */
    public static Weapon get(String weaponType) {
        if (weaponType == null || weaponType.trim().isEmpty()) {
            throw new RuntimeException("要生产生什么武器,请先告诉我~~");
        }
        Weapon weapon = switch (weaponType) {
            case "TANK" -> new Tank();
            case "FIGHTER" -> new Fighter();
            case "DAGGER" -> new Dagger();
            default -> throw new RuntimeException("不支持生产该武器~~");
        };
        return weapon;
    }
}

当我们要使用具体产品/对象的时候,我们不直接new了(对象是怎么生产出来的,怎和new的,有没有一些复杂的逻辑都不管了),而是让这个工厂帮我们去生产,我们只需要告诉它我们的需求即可。如下所示的客户端代码

public class Client {
    public static void main(String[] args) {
        Weapon weapon1 = WeaponFactory.get("TANK");
        weapon1.attack();

        Weapon weapon2 = WeaponFactory.get("FIGHTER");
        weapon2.attack();

        Weapon weapon3 = WeaponFactory.get("DAGGER");
        weapon3.attack();
    }
}

上面这种就是简单工厂模式,这种模式的优缺点如下:

优点:客户端不再关心产品创建的所有细节工作,需要哪个对象直接向工厂提需求即可。这样做到了职责分离。

缺点:对于某一个类型下的所有产品都是由工厂生产的,万一这个工厂类出点问题,怎么办?万一后面系统要扩展了,我们不得倒过去修改工厂类,这不符合OCP开闭原则啊!

工厂方法模式

工厂方法模式是对简单工厂模式的一种优化,它在工厂角色上再多了一个抽象工厂角色,所以它的角色分为如下一些:

抽象工厂角色、具体工厂角色、抽象产品角色、具体产品角色

我们通过代码来看一看

抽象产品

/**
 * 抽象产品角色
 */
public abstract class Weapon {
    public abstract void attack();
}

具体产品

/**
 * 具体产品角色
 */
public class Gun extends Weapon {
    @Override
    public void attack() {
        System.out.println("开枪射击~~");
    }
}

/**
 * 具体产品角色
 */
public class Fighter extends Weapon {
    @Override
    public void attack() {
        System.out.println("战斗机攻击~~");
    }
}

抽象工厂角色

/**
 * 抽象工厂角色
 */
public interface WeaponFactory {
    Weapon get();
}

具体工厂角色

/**
 * 具体工厂角色
 */
public class GunFactory implements WeaponFactory {
    @Override
    public Weapon get() {
        return new Gun();
    }
}

/**
 * 具体工厂角色
 */
public class FighterFactory implements WeaponFactory {
    @Override
    public Weapon get() {
        return new Fighter();
    }
}

最终客户端需要哪个产品直接找对应的工厂索要即可

public class Client {
    public static void main(String[] args) {
        WeaponFactory factory = new GunFactory();
        Weapon gun = factory.get();
        gun.attack();

        WeaponFactory factory1 = new FighterFactory();
        Weapon fighter = factory1.get();
        fighter.attack();
    }
}

这个时候我们可以看到当我们想要扩展一个新的产品时,不会动到现有结构,我们只需要新增一个具体产品类,同时再新增一个对应的具体工厂即可。

工厂方法模式的又有哪些优缺点呢?

优点:扩展性高

缺点:每增加一个产口就需要增加一个具体类的对象实现工厂,类的数量增长过快,在一定程度上增加了系统的复杂度。

抽象工厂模式

抽象工厂模式相对于工厂方法模式做了一个折中的处理,工厂方法模式是一个产品对一个工厂类,而抽象工厂模式是多个产品对应一个工厂类。

抽象工厂模式会把产品进行分类,每一类产生提供一个具体的生产工厂

抽象工厂模工中有如下四个角色

抽象工厂角色、具体工厂角色、抽象产品角色、具体产品角色

抽象产品

/**
 * 抽象产品族 - 武器
 */
public abstract class Weapon {
    public abstract void attack();
}


/**
 * 抽象产品族 - 水果
 */
public abstract class Fruit {
    /**
     * 水果的甜度
     */
    public abstract void sweetness();
}

具体产品

/**
 * 武器产品 - Gun
 */
public class Gun extends Weapon {
    @Override
    public void attack() {
        System.out.println("开枪射击~~");
    }
}

/**
 * 武器产品 - Dagger
 */
public class Dagger extends Weapon {
    @Override
    public void attack() {
        System.out.println("匕首砍~~~");
    }
}


/**
* 水果产品 - Grape
*/
public class Grape extends Fruit {
    @Override
    public void sweetness() {
        System.out.println("草莓甜度 - 高");
    }
}


/**
* 水果产品 - Blueberry
*/
public class Blueberry extends Fruit {
    @Override
    public void sweetness() {
        System.out.println("葡萄甜度 - 中");
    }
}

抽象工厂

/**
 * 抽象工厂类
 */
public abstract class AbstractFactory {
    public abstract Fruit getFruit(String fruitType);
    public abstract Weapon getWeapon(String weaponType);
}

具体工厂

/**
 * 具体工厂类 - 武器
 */
public class WeaponFactory extends AbstractFactory {
    @Override
    public Fruit getFruit(String fruitType) {
        return null;
    }

    @Override
    public Weapon getWeapon(String weaponType) {
        if(weaponType == null || weaponType.isEmpty()) {
            throw new RuntimeException("请提供具体要生产的武器~~");
        }
        return switch(weaponType) {
            case "Gun" -> new Gun();
            case "Dagger" -> new Dagger();
            default -> throw new RuntimeException("无法产生该武器~~");
        };
    }
}


/**
 * 具体工厂类 - 水果
 */
public class FruitFactory extends AbstractFactory {
    @Override
    public Fruit getFruit(String fruitType) {
        if(fruitType == null || fruitType.isEmpty()) {
            throw new RuntimeException("请提供具体要生产的水果~~");
        }
        return switch(fruitType){
            case "grape" -> new Grape();
            case "blueberry" -> new Blueberry();
            default -> throw new RuntimeException("不支持的水果类型");
        };
    }

    @Override
    public Weapon getWeapon(String weaponType) {
        return null;
    }
}

客户端在使用时可以如下:

// 测试程序
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory = new FruitFactory();
        Fruit blueberry = factory.getFruit("blueberry");
        blueberry.sweetness();
        Fruit grape = factory.getFruit("grape");
        grape.sweetness();
        System.out.println("=======================================");
        factory = new WeaponFactory();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值