Skip to content

EmmanueleVilla/SimpleServiceLocator

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 

Repository files navigation

SimpleLocator

SimpleLocator is a lightweight and fast Service Locator library for android that took inspiration from Splat for Xamarin.

  • No reflection
  • No generated code
  • No annotation
  • Simple to setup, simple to use: just initialize its rules and you are ready to go!
  • Ability to add, modify and remove rules at runtime
  • No need to add work to have it working in a multiple modules project (see below 'Multi Module Project')
  • Unit test friendly (see below 'Best practices')
  • Basic and singleton registration

Download

How to import

Add the repository to the main project gradle file

repositories {
    maven {
        url  "https://dl.bintray.com/willyrs/SimpleLocator" 
    }
}

Add the library to the module gradle file (check latest version in the badge above)

dependencies {
    implementation 'com.shadowings.simplelocator:simplelocator:VERSION'
}

Basic usage

Your interface

public interface MySampleInterface {
    String getMessage();
}

Your concrete class

public class MySampleConcreteClass implements MySampleInterface {
    @Override
    public String getMessage() {
        return "TEST!";
    }
}

Define the rule:

SimpleLocator.register(
    MySampleInterface.class,
    new ObjectFactory<MySampleInterface>() {
        @Override
        public MySampleInterface build() {
            return new MySampleConcreteClass();
        }
    }
);

If you are using java 8, the rule is very simple:

SimpleLocator.register(
    MySampleInterface.class,
    MySampleConcreteClass::new
);

Retrieve the concrete class

MySampleInterface concrete = SimpleLocator.get(MySampleInterface.class);

Of course, you can also register a class to itself

SimpleLocator.register(
    MySampleConcreteClass.class,
    MySampleConcreteClass::new
);

Singleton

In the same way, one can register a class to be a singleton:

SimpleLocator.registerSingleton(
    MySampleInterface.class,
    MySampleConcreteClass::new
);

In this way, SimpleLocator will always return the same instance of MySampleConcreteClass

Register with names

You can also pass a name when registering to register constants:

SimpleLocator.register(
    String.class, 
    "FirstName", 
    () -> "This is the first name string"
);

SimpleLocator.register(
    String.class, 
    "SecondName", 
    () -> "This is the second name string"
);

SimpleLocator.get(String.class, "FirstName"); //contains "This is the first name string"
SimpleLocator.get(String.class, "SecondName"); //contains "This is the second name string"

Multiple Registration

If you register the same class more times, SimpleLocator will consider only the last one

SimpleLocator.register(
    MySampleInterface.class,
    MySampleConcreteClass::new
);
SimpleLocator.register(
    MySampleInterface.class,
    MyOtherSampleConcreteClass::new
);
MySampleInterface concrete = SimpleLocator.get(MySampleInterface.class);
assertTrue(concrete instanceof MyOtherSampleConcreteClass)

Multi Module Project

SimpleLocator is particulary useful when you have a project with more than one module that aren't in a circular dependency (and that's the reason it was created!) For example, suppose that you need to develop an application for mobile and wear.
You probably will have this module configuration:

  • An App module
  • A Wear module
  • An android library module for the common code

SimpleLocator makes easy declaring an interface in the library module and use its methods while the concrete class is declared in the specific platform module!
You just need to create MyInterface in the library module and create MyWearImpl and MyAppImpl in the respective modules. Then, in the application startup, simply register them as seen previously!

//App module
SimpleLocator.register(
    MyInterface.class,
    MyAppImpl::new
);

//Wear module
SimpleLocator.register(
    MyInterface.class,
    MyWearImpl::new
);

//Library module will have the correct implementation
MyInterface concrete = SimpleLocator.get(MyInterface.class);

Best practices

Using SimpleLocator doesn't mean that it's hard to mock your dependencies: to have it working alongside unit tests, consider to write your classes something like this:

public class MainViewModel {

    private MySampleInterface mySampleInterface;

    public void setMySampleInterface(MySampleInterface mySampleInterface) {
        this.mySampleInterface = mySampleInterface;
    }

    public String getMessage()
    {
        //we are executing the concrete class from the other module without depend on it, yay!
        return this.mySampleInterface.getMessage();
    }
}

Then, register the rules like this:

SimpleLocator.register(MySampleInterface.class, MySampleConcreteClass::new);
SimpleLocator.register(MainViewModel.class, () -> {
    MainViewModel viewModel = new MainViewModel();
    viewModel.setMySampleInterface(SimpleLocator.get(MySampleInterface.class));
    return viewModel;
});

In this way, you can create the MainViewModel instance by simply calling:

MainViewModel mainViewModel = SimpleLocator.get(MainViewModel.class);

While in the unit tests, you will create it like this:

MainViewModel viewModel = new MainViewModel();
viewModel.setMySampleInterface(MySampleInterfaceMockForUnitTests);

About

Simple and fast service locator for android

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages