Хочу поделиться с вами своим опытом изучения парадигмы АОП и разработки с её использованием в крупном проекте.
Аспектно-ориентированное программирование, или АОП, — парадигма, которая выделяет сквозной функционал и изолирует его в виде так называемого аспекта, или аспектного класса. Подразумевается наличие семантических инструментов и механизмов «подкапотной» инъекции аспекта в код приложения. Таким образом, получается, что аспект сам определяет, какие участки приложения ему нужно обрабатывать, в то время как приложение и не догадывается (до компиляции, конечно), что в его участки нагло и бессовестно вводят чужеродный код.
Допустим, что у нас есть довольно тривиальная задача — обеспечить приложению поддержку некоторых языков (russian, english, italian, french, etc.). Вы скажете, что у нас есть языковая и региональная дифференциация всех ресурсов, и будете правы. За исключением случая, когда приложение пользуется не встроенными ресурсами, а «тянет» их с сервера. В общем-то, такая ситуация встречается часто и решается тривиально — добавляем в абстрактный класс BaseActivity, который у нас наследуется от системного, пару строчек на обработчик, и всё работает. А можно обойтись и без этих пары строчек. И даже без базового класса. А при необходимости — просто скопировать в приложение один файл или добавить зависимость в gradle, которая всё сделает сама.
Итак, задача ясна, пишем.
package com.archinamon.example.xpoint;
import android.support.v7.app.AppCompatActivity;
import android.app.Application;
public aspect LocaleMonitor {
pointcut saveLocale(): execution(* MyApplication.onCreate());
pointcut checkLocale(AppCompatActivity activity): this(activity) && execution(* AppCompatActivity+.onCreate(..));
after(): saveLocale() {
saveCurrentLocale();
}
before(AppCompatActivity activity): checkLocale(activity) {
if (isLocaleChanged()) {
saveCurrentLocale();
restartApplication(activity);
}
}
void saveCurrentLocale() {/* implementation */}
void restartApplication(AppCompatActivity context) {/* implementation */}
boolean isLocaleChanged() {/* implementation */}
}
Добавив этот класс в наше приложение, мы научим его перезапускать само себя при смене языка в системе.
Некоторое время я искал готовые решения и пробовал их на вкус. В итоге написал свой вариант. Как это всё работает, зачем пришлось изобретать велосипед и что из всего этого вышло — под катом!