手动实现“低配版”IOC

引言

IOC,全称Inversion of Control,控制反转。也算是老生常谈了。java

老生常谈:原指老书生的平凡议论;今指常讲的没有新意的老话。

同时另外一个话题,依赖注入,用什么就声明什么,直接就声明,或者构造函数或者加注解,控制反转是实现依赖注入的一种方式。程序员

经过依赖注入:咱们无需管理对象的建立,经过控制反转:咱们能够一键修改注入的对象。spring

最近在作Android实验与小程序相关的开发,发现用惯了IOC的咱们再去手动new对象的时候总感受内心不舒服,之后改起来怎么办呢?既然没有IOC,咱们就本身写一个吧。小程序

实现

就像我在标题中描述的同样,我先给你们讲解一下标配IOC的原理,使你们更清晰明了,可是受Android与小程序相关的限制,我具体的实现,是低配版IOC服务器

我的扯淡

不论是Spring仍是Angular,要么是开源你们,要么是商业巨头,具体的框架实现都是至关优秀。我还没水平也没精力去研读源码,只但愿分享本身对IOC的理解,帮到更多的人。网络

毕竟如今小学生都开始写Python,之后的框架设计会愈来愈优秀,学习成本愈来愈低,开发效率愈来愈高。多是我的报个培训班学个俩月也会设计微服务,也能成为全栈工程师。因此咱们应该想的是如何设计框架,而不是仅停留在使用的层面,渐渐地被只会写增删改查每天搬砖的人取代。框架

996加班的工程师都开始挤时间写框架扩大影响力,让社会听到程序员的呐喊,咱们还有什么不努力的理由?ide

clipboard.png

“标配”IOC

不论是Spring仍是Angular,它们的核心是什么呢?打上mvn spring-boot:run后台就Started Application in xxx seconds了,它到底干什么了呢?函数

clipboard.png

容器

SpringAngular就是一个大的IOC容器,因此应用启动的过程,其实就是构造容器的过程。spring-boot

clipboard.png

容器,确定是装东西的啊?IOC容器里装的是什么?

装的是对象。控制器Controller,服务Service,自定义的组件Component,全部被Spring管理的对象都将被放进IOC容器里。

clipboard.png

因此,你们应该能明白,为何IOC是依赖注入的一种实现方式?

由于这个对象不是你本身new的,是从容器中拿的,容器初始化的时候,就已经把这个对象构造好了,该注的都注进来了。

思考

从上面你们能够看到,依赖注入的前提是什么?是要求这个对象必须是从容器中拿的,因此才能依赖注入成功。

Spring Boot中没问题,Tomcat转发的路由直接交给容器中相应的对象去处理,同理,Angular也同样。

Android呢?

clipboard.png

手机调用的并非咱们构造的Activity,而是它本身实例化的,小程序也与之相似,Page的实例化不归咱们管。

因此“标配”IOC在这里不适用,因此我设计了“低配”IOC容器。

“低配”IOC

找点本身能管得了的对象放在IOC容器里,这样再须要对象就不用去new了,Service有变动直接修改注入就好了。

受咱们管理的只有Service,计划设计一个管理全部ServiceIOC容器,而后ActivityPage里用的时候,直接从容器中拿。(低配在这里,不能依赖注入了,得本身拿)。

clipboard.png

Android

一个单例的Configuration负责注册Bean和获取Bean,存储着一个context上下文。看着挺高级的,其实就是一个HashMap存储着接口类型容器对象的映射。

/**
 * 全局配置类
 */
public class Configuration {

    private static Map<Class<?>, Object> context = new HashMap<>();

    private static final class Holder {
        private static final Configuration INSTANCE = new Configuration();
    }

    public static Configuration getInstance() {
        return Holder.INSTANCE;
    }

    public Configuration registerBean(Class<?> clazz, Object bean) {
        context.put(clazz, bean);
        return this;
    }

    public <T> T getBean(Class<?> clazz) {
        return (T) context.get(clazz);
    }
}

写一个静态方法,更加方便配置。

/**
 * 云智,全局配置辅助类
 */
public class Yunzhi {

    ...

    public static <T> T getBean(Class<?> clazz) {
        return Configuration.getInstance().getBean(clazz);
    }
}

一个Application负责容器中全部对象的建立。

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        Yunzhi.init()
                .setApi("http://192.168.2.110:8888")
                .setTimeout(1L)
                .registerBean(AuthService.class, new AuthServiceImpl())
                .registerBean(LetterService.class, new LetterServiceImpl());
    }
}

使用方法和原来就同样了,一个接口,一个实现类。这里用到了RxJava,看上去却是相似咱们的Angular了。

public interface AuthService {

    Observable<Auth> login(String username, String password);
}
public class AuthServiceImpl implements AuthService {

    private static final String TAG = "AuthServiceImpl";

    @Override
    public Observable<Auth> login(String username, String password) {
        Log.d(TAG, "BASIC 认证");
        String credentials = username + ":" + password;
        String basicAuth = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

        Log.d(TAG, "请求登陆");
        return HttpClient.request(AuthRequest.class)
                .login(basicAuth)
                .subscribeOn(Schedulers.io())                   // 在IO线程发起网络请求
                .observeOn(AndroidSchedulers.mainThread());     // 在主线程处理
    }
}

由于Activity咱们管不着,因此在Activity里用不了依赖注入,须要手动从容器里拿。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.authService = Yunzhi.getBean(AuthService.class);
}

这里有一处没考虑到的问题,就是手机端的性能问题,手机和服务器的处理能力确定是比不了的,服务器在初始化的时候把全部对象都建立处理无可厚非,可是感受手机端这样作仍是会对性能产生必定影响的。

应该是某些对象用到的时候再建立,实验要求时间很紧,这个就先这样吧,不改了。

小程序端

小程序是在Android以后写的,想到了以前设计的部分缺陷,对容器使用了另外一种思想进行实现。

export class YunzhiService {

    private static context = new Map<string, object>();

    public static getBean(beanName: string): object {
        // 从context里拿对象
        let bean = this.context.get(beanName);
        // 若是没有,构造一个,并放进context
        if (!bean) {
            bean = this.createBeanByName(beanName);
            this.context.set(beanName, bean);
        }
        // 返回
        return bean;
    }

    public static createBeanByName(beanName: string): object {
        // 根据不一样名称构造不一样的Bean
        switch (beanName) {
            case Bean.AUTH_SERVICE:
                return new AuthServiceImpl();
            case Bean.SCORE_SERVICE:
                return new ScoreServiceImpl();
            case Bean.SEMESTER_SERVICE:
                return new SemesterServiceImpl();
            default:
                throw '错误,未注册的bean';
        }
    }
}

总结

Spring Boot真厉害,何时咱们也能写出如此优秀的框架?

相关文章
相关标签/搜索