“trait”的依赖注入

时间:2015-07-04 01:16:32

标签: scala dependency-injection

鉴于以下FooService

scala> trait FooService { 
     |   def go: Int 
     | }
defined trait FooService

还有一个MainService,代表一种主要方法。

scala> trait MainService extends FooService { 
     |   def f = go + 42
     | }
defined trait MainService

FooService可以有假(用于测试)和实际实现(例如命中数据库):

scala> object FakeService extends FooService { 
     |   def go = 10
     | }
defined object FakeService

scala> object RealService extends FooService {
     |   def go = 55 // in reality, let's say it hit the DB and got a value
     | }
defined object RealService

在我看来,添加一个"跑步者" class / trait,即运行sbt run将导致该类的执行,是可行的。它看起来像是:

scala> class Main extends MainService {
     |   override def go = RealService.go
     | }
defined class Main

我也可以定义一个测试:

scala> class Test extends MainService {
     |   override def go = FakeService.go
     | }
defined class Test

我不太确定这是定义真实与测试MainService的惯用方法。请告诉我。

1 个答案:

答案 0 :(得分:4)

您可以使用流行的蛋糕模式,也称为" Scala方式"做依赖注入。

Jon通过演练对此做了很好的blog post(他还列出了一些替代方案)。

首先,FooService

的特征
trait FooServiceComponent {
  val fooService: FooService

  trait FooService {
    def go: Int
  }
}

这就是说,我们需要两件事:1。实际对象,2。它的定义/实现。两者都命名在一起。尼斯。以下是FakeReal版本:

trait FakeService extends FooServiceComponent {
  class FakeService extends FooService {
    def go = 10
  }
}

trait RealService extends FooServiceComponent {
  class RealService extends FooService {
    def go = 55
  }
}

现在,对于MainService

trait MainServiceComponent { this: FooServiceComponent =>
  val mainService: MainService

  class MainService extends FooService {
    def f = go + 42
    def go = fooService.go // using fooService
  }
}

请注意自键入this: FooServiceComponent,这是一种Scala方式,表示MainServiceComponent依赖于FooServiceComponent。如果您尝试在MainServiceComponent中实例化FooServiceComponent而不混合任何Test,那么您将收到编译时错误。尼斯。 :)

现在,让我们创建具有不同特征的Mainobject Test extends MainServiceComponent with FakeService { val mainService = new MainService() val fooService = new FakeService() } object Main extends MainServiceComponent with RealService { val mainService = new MainService() val fooService = new RealService() } 个对象:

FakeService

请注意,由于命名空间,Main无法在println(Test.mainService.f) // -> 52 println(Main.mainService.f) // -> 97 中访问,因为它没有混入。很好。 :)还要注意你延迟任何类的实例化,直到这一点,这很方便,你可以很容易地使用注册表或模拟库在一个地方替换它们。

结果:

 function upload_barang(){

    $this->admin_model->login();

    $this->admin_model->valid_product();

    $config['upload_path'] = './produk/';
    $config['allowed_types'] = 'jpg';
    $config['max_size'] = '100';
    $config['max_width']  = '400';
    $config['max_height']  = '400';

    $this->load->library('upload',$config); 

    $data['query'] = $this->db->get('kategori');

     if($this->form_validation->run() == FALSE && ! $this->upload->do_upload()) {

     $data['error'] = $this->upload->display_errors();

     $data['success'] = '';

     $this->load->view('backoffice/tambahbarang',$data);

     } else {

       $upload_data = $this->upload->data();

      $data['error'] = '';

      $data = array(
      'idkategori' => $this->input->post('idkategori'),
      'namabarang' => $this->input->post('nbarang'),
      'image' =>  $upload_data['file_name'],
      'status' => 1
   );

    $data_insert = $this->db->insert('barang',$data);

    if($data_insert == TRUE) {

      $data['query'] = $this->db->get('kategori');

      $query = $this->db->get('barang');

      $rows = $query->row();

      $data['idbarang'] = $rows->idbarang; 

      $harga = array(
      'idbarang' => $data['idbarang'],
      'satuan' => $this->input->post('stcbarang'),
      'harga' => $this->input->post('hbarang')
   );

   $this->db->insert('hargabarang',$harga);

   $data['success'] = '<b>Barang Telah Ditambahkan</b>';

    $this->load->view('backoffice/tambahbarang',$data);  

   } else {

    $data['success'] = '<b>Barang Gagal Ditambahkan</b>';

    $this->load->view('backoffice/tambahbarang',$data);  

    }

  }  
} 

我希望这会有所帮助。