反射与工厂模式:早餐店的发展之路

实际开发中,接口的主要作用是为了不用层提供有一个操作的标准,如果直接实例化了类的操作【用new关键字来实例化】,则一定存在耦合问题,可以用工厂模式解决此问题。

接下来用一个店主开早餐店的经历来阐述反射与工厂模式。

店主的经历如下:简单的早餐店 --> 增加西式早餐 --> 多种早餐需求 --> 拓展业务。

简单的早餐店

店主起初想开个简单的早餐店,就经营简单的早餐业务,所以创建了一个简单的工厂来生产对应的早餐服务。

BreakfastService

package javabase.service;
public interface BreakfastService {
    void cookIt();
}

Breakfast

package javabase.entity;
import javabase.service.BreakfastService;
public class Breakfast implements BreakfastService {
    @Override
    public void cookIt() {
        System.out.println("====我正在做一份美味的早餐呢!====>");
    }
}

MyFactory

package javabase.factory;
import javabase.entity.Breakfast;
import javabase.service.BreakfastService;
public class Myfactory {
    private Myfactory(){

    }
    public static BreakfastService getBreakFast(String name){
        //判断传来的是否是美味的早餐的名字
        if("Breakfast".equals(name)){
            //如果是则返回对应的实例化对象
            return new Breakfast();
        }
        return null;
    }
}

Main

package javabase;
import javabase.factory.Myfactory;
import javabase.service.BreakfastService;
public class Main {
    public static void main(String[] args) {
        //开始买早餐咯
        BreakfastService breakfastService = Myfactory.getBreakFast("Breakfast");
        breakfastService.cookIt();
    }
}

运行结果

====我正在做一份美味的早餐呢!====>

增加西式早餐

店主开店之后,生意火爆,有顾客跟店长反应,要不再开多一个西式的早餐业务?店主想了想,如果品种再多一点的话,说不定客户会更多呢!于是就创建了对应的西式早餐服务,然后再添加到对应的工厂里。

EastBreakfast

package javabase.entity;
import javabase.service.BreakfastService;
public class EastBreakfast implements BreakfastService {
    @Override
    public void cookIt() {
        System.out.println("====我正在做一份美味的西式早餐呢!====>");
    }
}

那么店主的工厂得开始加工了,再来生产西式早餐。

MyFactory

package javabase.factory;
import javabase.entity.Breakfast;
import javabase.entity.EastBreakfast;
import javabase.service.BreakfastService;
public class Myfactory {
    private Myfactory(){

    }
    public static BreakfastService getBreakFast(String name){
        //根据客户端传入的名字来判断客户端需要什么早餐
        if("Breakfast".equals(name)){
            //返回普通早餐的实例化
            return new BreakFast();
        }else if("EastBreakfast".equals(name)){
            //返回西式早餐的实例化
            return new EastBreakfast();
        }
        return null;
    }
}

Main

package javabase;
import javabase.factory.Myfactory;
import javabase.service.BreakfastService;
public class Main {
    public static void main(String[] args) {
        //生产美味的早餐
        BreakfastService breakfastService = Myfactory.getBreakFast("Breakfast");
        breakfastService.cookIt();
        //生产美味的西式早餐
        BreakfastService eastBreakfast = Myfactory.getBreakFast("EastBreakfast");
        eastBreakfast.cookIt();
    }
}

运行结果

====我正在做一份美味的早餐呢!====>
====我正在做一份美味的西式早餐呢!====>

多种早餐需求

要知道,顾客就是上帝,近期许多顾客都向店主提要求说要中式早餐,日式早餐等不同品种的早餐?要是像增加西式早餐那样直接添加对应的实例化西式早餐对象代码的话,日后代码就变得冗长且难读,而且会浪费大量的时间在阅读工厂代码以及修改工厂代码上。如果每天店主都这样工作的话,恐怕会英年早逝。

这次店长灵光一闪,想到用反射来进行获取对应的早餐,所以工厂的代码修改如下。

MyFactory

//少了两行import *^_^*
package javabase.factory;
import javabase.service.BreakfastService;
public class Myfactory {
    private Myfactory(){

    }
    public static BreakfastService getBreakFast(String breakfastName){
        BreakfastService breakfastService = null;
        try {
            /**
             *  使用反射的方式来获取对应的早餐实例化对象
             *  使用Class的static方法forName(name)获取Class的实例化对象
             *  再调用newInstance()方法来实例化BreakfastService
             *  最后再进行类型转化
             */
            breakfastService = (BreakfastService)Class.forName(breakfastName).newInstance();
        } catch (Exception e) {
            //如果出现任何异常直接返回null
            return null;
        }
        return breakfastService;
    }
}

Main

package javabase;
import javabase.factory.Myfactory;
import javabase.service.BreakfastService;
public class Main {
    public static void main(String[] args) {
        //生产美味的早餐,这次需要传递的就是完整的类名了【包.类】,就不能简单地写类名了
        BreakfastService breakfastService = Myfactory.getBreakFast("javabase.entity.Breakfast");
        breakfastService.cookIt();

        //生产美味的西式早餐
        BreakfastService eastBreakfastService = Myfactory.getBreakFast("javabase.entity.EastBreakfast");
        eastBreakfastService.cookIt();
    }
}

运行结果

====我正在做一份美味的早餐呢!====>
====我正在做一份美味的西式早餐呢!====>

这时,店主再加入中式早餐服务,则不需要再修改对应的工厂类。

ChineseBreakfast

package javabase.entity;

import javabase.service.BreakfastService;

public class ChineseBreakfast implements BreakfastService {
    @Override
    public void cookIt() {
        System.out.println("====我正在做一份美味的中式早餐呢!====>");
    }
}

Main

package javabase;
import javabase.factory.Myfactory;
import javabase.service.BreakfastService;
public class Main {
    public static void main(String[] args) {
        //生产美味的早餐,这次需要传递的就是完整的类名了【包.类】,就不能简单地串类名了
        BreakfastService breakfastService = Myfactory.getBreakFast("javabase.entity.Breakfast");
        breakfastService.cookIt();

        //生产美味的西式早餐
        BreakfastService eastBreakfastService = Myfactory.getBreakFast("javabase.entity.EastBreakfast");
        eastBreakfastService.cookIt();

        //生产中式早餐
        BreakfastService chineseBreakfastService = Myfactory.getBreakFast("javabase.entity.ChineseBreakfast");
        chineseBreakfastService.cookIt();
    }
}

运行结果

====我正在做一份美味的早餐呢!====>
====我正在做一份美味的西式早餐呢!====>
====我正在做一份美味的中式早餐呢!====>

拓展业务

通过反射的机制,店长有了更多的时间来进行思考其他的事,时间也更加充裕了。店长又突发奇想,如果我们的店再兼做午餐和晚餐会怎样呢?加多几个工厂如何?可是如果未来要发展更多的餐饮业务,就要加更多个工厂,那每个工厂维护起来,岂不是要麻烦死,店长可不想因为此事而秃顶。店长经过上次经历后,决定,用泛型加反射来搞事情。

所以店长又再次决定修改工厂代码,加入泛型。

MyFactory

package javabase.factory;
import javabase.service.BreakfastService;
public class Myfactory {
    private Myfactory(){

    }
    public static <T> T getService(String serviceName){
       T service = null;
        try {
             /**
             *  使用反射的方式来获取对应的早餐实例化对象
             *  使用Class的static方法forName(name)获取Class的实例化对象
             *  再调用newInstance()方法来实例化BreakfastService
             *  最后再进行类型转化,这里用泛型的转化
             */
            service = (T) Class.forName(serviceName).newInstance();
        } catch (Exception e) {
            //如果出现任何异常直接返回null
            return null;
        }
        return service;
    }
}

此时,店长再加入午餐业务

LunchService

package javabase.service;
public interface LunchService {
    void cookLunch();
}

加入中式午餐服务

package javabase.entity;
import javabase.service.LunchService;
public class ChineseLunch implements LunchService {
    @Override
    public void cookLunch() {
        System.out.println("====我正在做一份不一样的中式午餐呢!====>");
    }
}

两种业务进行,同个工厂进行生产两种不同的业务

Main

package javabase;
import javabase.factory.Myfactory;
import javabase.service.BreakfastService;
import javabase.service.LunchService;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        //生产中式早餐 --->早餐业务
        BreakfastService breakfastService = Myfactory.getService("javabase.entity.ChineseBreakfast");
        breakfastService.cookIt();

        //生产中式午餐 --->午餐业务
        LunchService lunchService = Myfactory.getService("javabase.entity.ChineseLunch");
        lunchService.cookLunch();
    }
}

运行结果

====我正在做一份美味的中式早餐呢!====>
====我正在做一份不一样的中式午餐呢!====>

最后,店主总算是可以拓展不同的餐饮领域了,不用再操心工厂生产的事咯!

总结

1.使用反射可以获取实例化对象的内容,与工厂模式结合能大大的减少代码中实例化对象的耦合。

2.最后使用泛型,而不直接使用Object呢?实际上最后的代码用Object也是可行的,但是在使用的时候要强制转化类型,而泛型则不用,相对来说,编译也会相对于Object安全。讲得通俗点就是,人家java底层开发人员开发出来个比原来还差的东西岂不是要被喷死。

3.代码的实用性以及扩展性,实用反射和泛型之后,能够很好的遵守开闭原则,就尽量减少对原来代码的修改。

4.减少代码的冗余,是检验代码质量的最基本要求,最好就做到高复用,低耦合啦。

5.代码的复制粘贴可能会有错误,参考的游客可以自行尝试敲下代码增加下印象,如果这篇博客能帮助你理解反射与工厂模式之间的关系就更好了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值