 
 
 
  
  Fruit教程翻译: 3. 有辅助的注入, 3. Assisted injection
在教程的这个部分,我们会构造 一个组件,它的作用是, 按照某个常数因子 ,将双精度浮点数放大对应的倍数。完整 的源代码在这里: examples/scaling_doubles 。
首先,编写一个Multiplier 组件。
   
    // multiplier.h
   
   
    
    
   
   
    class Multiplier {
   
   
    
   
   
    public:
   
   
    
   
   
      // 返回
   
   
    x和y的乘积。
   
   
    
   
   
      virtual double multiply(double x, double y) = 0;
   
   
    
   
   
    };
   
   
    
    
   
   
    fruit::Component<Multiplier> getMultiplierComponent();
   
  
   
    // multiplier.cpp
   
   
    
    
   
   
    #include "multiplier.h"
   
   
    
    
   
   
    class MultiplierImpl : public Multiplier {
   
   
    
   
   
    public:
   
   
    
   
   
      double multiply(double x, double y) override {
   
   
    
   
   
        return x * y;
   
   
    
   
   
      }
   
   
    
   
   
    };
   
   
    
   
   
    
     
fruit::Component<Multiplier> getMultiplierComponent() {
  return fruit::createComponent()
    .bind<Multiplier, MultiplierImpl>()
    .registerConstructor<MultiplierImpl()>();
}
   
  
如本例所示,如果某个接口存在着一个标准实现,那么,我们可以将该接口的定义和get*Component()函数的声明放置在同一个头文件中,以省掉一些繁琐的代码。
注意 , MultiplierImpl 的构造函数 并未 使用 INJECT() 包装起来 。 那是一种用来向Fruit 告知 该使用哪个注入器的便利方式,但是, 在某些情况下,无法使用那种方式,例如, MultiplierImpl可能 是由另一个并未使用Fruit 的项目提供的。 本示例中,我们实际上可以使用那种方式,但是, 我们就是不使用,以展示 另一种(等价的)方式,即,显式地使用构造函数 的原型来调用registerConstructor。
   
    // scaler.h
   
   
    
    
   
   
    class Scaler {
   
   
    
   
   
    public:
   
   
    
   
   
      virtual double scale(double x) = 0;
   
   
    
   
   
    };
   
   
    
    
   
   
    using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
   
   
    
    
   
   
    fruit::Component<ScalerFactory> getScalerComponent();
   
  
   一开始,妳可能争着要去编写
   
    Component<Scaler>
   
   。但是,
   我们并没有单个的
   Scaler实现,而且,对于每个
   双精度浮点数值(即为因子),都存在一个
   Scaler实现
   。所以
   ,我们在组件原型中暴露这一点。
   在返回数值类型时,
   我们可以直接以数值的形式来返回,但是
   ,对于接口来说,最好
   是返回一个
   unique_ptr
   ,以确保
   该对象会被销毁。
   Fruit
   可以注入任意类,但是
   ,对于像
   
    std::function<std::unique_ptr<T>(...)>
   
   这种形式的类型,有着特殊的支持,我们狠快会看到。
   
    
现在开始
   写实现代码。
  
   
    // scaler.cpp
   
   
    
    
   
   
    #include "scaler.h"
   
   
    
   
   
    #include "multiplier.h"
   
   
    
    
   
   
    using fruit::Component;
   
   
    
   
   
    using fruit::Injector;
   
   
    
   
   
    using fruit::createComponent;
   
   
    
    
   
   
    class ScalerImpl : public Scaler {
   
   
    
   
   
    private:
   
   
    
   
   
      Multiplier* multiplier;
   
   
    
   
   
      double factor;
   
   
    
   
   
    
   
   
    
   
   
    public:
   
   
    
   
   
      INJECT(ScalerImpl(ASSISTED(double) factor, Multiplier* multiplier))
   
   
    
   
   
        : multiplier(multiplier), factor(factor) {
   
   
    
   
   
      }
   
   
    
   
   
    
   
   
    
   
   
      double scale(double x) override {
   
   
    
   
   
        return multiplier->multiply(x, factor);
   
   
    
   
   
      }
   
   
    
   
   
    };
   
   
    
    
   
   
    Component<ScalerFactory> getScalerComponent() {
   
   
    
   
   
      return createComponent()
   
   
    
   
   
        .bind<Scaler, ScalerImpl>()
   
   
    
   
   
        .install(getMultiplierComponent());
   
   
    
   
   
    }
   
  
此处 ,我们首次见到了 ASSISTED() 宏。 它的作用是, 在一个被 INJECT() 包装的构造函数中,标记 出某些不需要被注入的类型,那些类型 会成为被注入的工厂函数的参数。
注意,此处,我们直接安装了这个乘法器组件,而不是将它声明为需求再编写一个将ScalerImplComponent 和MultiplierComponent 复合起来的组件。这是一个折衷:这样做,会稍微削弱模块化特性,但是,会使代码更简洁(避免写出2个文件)。至于空间哪种实现方式更好呢,没有绝对的答案;这种折衷,必须根据具体的情况来评估。
注意 ,此处绑定操作也做了某些不同的事情: 我们没有将 Scaler绑定 到 ScalerImpl , 而是将一个 std::function<std::unique_ptr<Scaler>(double)> 绑定到一个 std::function<std::unique_ptr<ScalerImpl>(double)> 。
   
    // main.cpp
   
   
    
    
   
   
    #include "scaler.h"
   
   
    
    
   
   
    using fruit::Injector;
   
   
    
    
   
   
    int main() {
   
   
    
   
   
      Injector<ScalerFactory> injector(getScalerComponent());
   
   
    
   
   
      ScalerFactory scalerFactory(injector);
   
   
    
   
   
    
   
   
    
   
   
      std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
   
   
    
   
   
      std::cout << scaler->scale(3) << std::endl;
   
   
    
   
   
    
   
   
    
   
   
      return 0;
   
   
    
   
   
    }
   
  
这就 是 main() 函数,现在应该 狠容易理解了。 我们从注入器获取了工厂的一个实例,然后,自己调用 该工厂的方法来获取Scaler 的一个实例。
现在,妳已经知道Fruit 的基本用法了。为了进一步熟悉它呢,建议妳尝试着重写上面展示的系统,或者,编写妳觉得有意思的任何其它系统,再改动一下代码,观摩其效果。
在 教程 的下一部分 中,我们将学习 到,Fruit 是如何报告注入错误的。
何 晴
Your opinionsHxLauncher: Launch Android applications by voice commands
