简单工厂模式

我们在写业务的时候,比如说三国杀或者一些卡牌游戏,设定了雷杀,火杀,这些牌都有一个特征就是指定一个人掉血,掉多少血,各不相同,那么我们就设定雷杀一血,火杀二血,水杀三血。
在设计的时候,我们很蠢的设计就是这样。
在这里插入图片描述
转化为代码,就是这样

    public static void main(String[] args) {
//        模拟输入
        String cardName="ThunderKill";
        switch (cardName){
            case "ThunderKill":
                new ThunderKill().kill();
                break;
            case "FireKill":
                new FireKill().kill();
                break;
            case "WaterKill":
                new WaterKill().kill();
                break;
        }

    }
    public class FireKill {
    public void kill(){
        System.out.println("火杀 -2血");
    }
    package card;

public class WaterKill {
    public void kill(){
        System.out.println("水杀 -3血");
    }
}
package card;

public class ThunderKill {
    public void kill(){
        System.out.println("雷杀 -1血");
    }
}


}

这样写有个坏处,那就是比如说我加了个土杀,然后新增个class,还得再新实例化一个对象出来,,对代码改动太大,那么我们改造一下,对其进行抽象化。

改造成这样,让用户不管执行的是哪个对象的杀,执行的就是杀,对象执行和初始化分开,这样的好处在于不用挨个去进行kill操作,只需判断实例化哪个对象就行。
在这里插入图片描述

    public static void main(String[] args) throws Exception {
        String cardName="ThunderKill";
        Card card;
        switch (cardName){
            case "ThunderKill":
                card=new ThunderKill();
                break;
            case "FireKill":
                card=new FireKill();
                break;
            case "WaterKill":
                card=new WaterKill();
                break;
            default:
                throw new Exception();
        }
        card.kill();
    }
    }
    public class FireKill {
    public void kill(){
        System.out.println("火杀 -2血");
    }
    package card;

public class WaterKill {
    public void kill(){
        System.out.println("水杀 -3血");
    }
}
package card;

public class ThunderKill {
    public void kill(){
        System.out.println("雷杀 -1血");
    }
}
public interface Card {
    public void kill();
}

这个版本的好处在于我们不管实例化哪个对象,直接在判断中实例出来,然后统一进行执行操作
这样还不够,我们再看一个版本
在这里插入图片描述

package card.v2;

import card.v2.cards.FireKill;
import card.v2.cards.ThunderKill;
import card.v2.cards.WaterKill;

public class CardFactory {
    static Card getCard(String cardName) throws Exception {
        Card card;
        switch (cardName) {
            case "ThunderKill":
                card = new ThunderKill();
                break;
            case "FireKill":
                card = new FireKill();
                break;
            case "WaterKill":
                card = new WaterKill();
                break;
            default:
                throw new Exception();
        }
        return card;
    }
}
    public static void main(String[] args) throws Exception {
        String cardName="ThunderKill";
        Card card=CardFactory.getCard(cardName);
        card.kill();

    }

至此为止,我们已经获得一个相对稳定的结构了,肤浅一点来说,看这个代码稳定与否,是写了多少个new是吗?
第一个版本的代码我们有Card就实例化一个Card,第二个版本我们先把Card抽象出来,按照传入的参数进行实例化,最后执行某个方法,第三个新建个工厂,将执行的这个功能的转移到工厂类中,需要什么对象,直接从工厂中获取,其实第二个版本和第三个版本本质上并没有太大区别,只是功能上的转移。
那么,我们能不能再有个更优雅一点的写法?
有,那就是映射
其实很多场景下我们使用映射并不多,但是映射的确比较好用。
先科普一下什么是元类,
首先类是对象的一种抽象,元类就是对类的一种描述
元类写法Class<?>clazz
我们来看最后一个版本的代码

    public Card getCard(String name) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> clazz = Class.forName(name);
        Object obj = clazz.getDeclaredConstructor().newInstance();
        return (Card) obj;
    }

我们首先用了反射中的元类进行查找这个类,再用映射给其实例化出了一个对象
那么值得注意的是,8以及8之前的jdk支持直接newInstance这个方法,但是8以后java就已经废弃了这个方法,所以现在需要声明一个构造函数再进行实例化操作。
这样我们就可以进行动态传值实例对象,是不是很有趣?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值