
今天想和大家分享一下Flux,F(xiàn)lux是Facebook用來(lái)構(gòu)建Web應(yīng)用的架構(gòu),目前在React中被廣泛使用。有這幾點(diǎn)需要注意,F(xiàn)lux是模式而不是框架,是單向數(shù)據(jù)流,是MVC最好的實(shí)踐。 至于為什么要使用Flux,我們可以看一個(gè)Facebook遇到的問(wèn)題。

一開(kāi)始,產(chǎn)品需求是聊天信息在右下角的chat View顯示,如果用戶沒(méi)有點(diǎn)擊,右上角出現(xiàn)紅色標(biāo)示,后來(lái)產(chǎn)品需要在中間的View中顯示,如果已經(jīng)被用戶看到,則右上角不出現(xiàn)紅色標(biāo)示,一段時(shí)間之后,產(chǎn)品又需要在左邊新增一個(gè)通訊錄列表,可以顯示最近的聊天信息,如果用戶看到,則右上角不出現(xiàn)紅色標(biāo)示。(沒(méi)有看錯(cuò),就是如此讓人不省心,哈哈。)
產(chǎn)品結(jié)構(gòu)如下:

然后我們看下代碼:

我們可以看到,隨著產(chǎn)品需求不斷地累加,代碼塊越來(lái)越臃腫,很不利于維護(hù),于是,F(xiàn)acebook推出了Flux,我們來(lái)看下Flux結(jié)構(gòu):

各模塊的介紹:
- View:視圖層
- Action(動(dòng)作):視圖層發(fā)出的消息
- Dispatcher(派發(fā)器):接收、派遣Action
- Store(數(shù)據(jù)層):接受派遣的Action,執(zhí)行業(yè)務(wù)邏輯,提醒Views更新

我們來(lái)看看在Android中如何使用,例子是一個(gè)TODO App,輸入Todo內(nèi)容,點(diǎn)擊添加按鈕,顯示輸入的Todo列表:

TodoActionCreator
Action生成器,創(chuàng)建CREATE和GET_ALL Action
public class TodoActionCreator {
public static final String ID = "id";
public static final String TEXT = "text";
public static final int ACTION_CREATE = 0;
public static final int ACTION_GET_ALL = 1;
private Dispatcher dispatcher;
......
public void create(String text) {
dispatcher.dispatch(ACTION_CREATE, TEXT, text);
}
public void getAll(){
dispatcher.dispatch(ACTION_GET_ALL);
}
}
Dispatcher
public class Dispatcher {
private static Dispatcher dispatcher;
private Store.OnStoreChangeListener onStoreChangeListener;
public Dispatcher(Store.OnStoreChangeListener onStoreChangeListener) {
this.onStoreChangeListener = onStoreChangeListener;
}
......
public void dispatch(int type, Object... data){
HashMap<String, Object> hashMap = new HashMap<>();
int i = 0;
while (i < data.length) {
String key = (String) data[i++];
Object value = data[i++];
hashMap.put(key, value);
}
Action action = new Action(type, hashMap);
if (!isTodoStore(action)) {
return;
}
Store store;
if (isTodoStore(action)) {
store = new TodoStore(onStoreChangeListener);
store.onAction(new Action(type, hashMap));
}
}
private boolean isTodoStore(Action action) {
return action.getType() == TodoActionCreator.ACTION_GET_ALL || action.getType() == TodoActionCreator.ACTION_CREATE;
}
}
TodoStore
public class TodoStore extends Store{
public TodoStore(OnStoreChangeListener onStoreChangeListener) {
super(onStoreChangeListener);
}
@Override
public void onAction(Action action) {
switch (action.getType()){
case TodoActionCreator.ACTION_CREATE:
create((String) action.getHashMap().get(TodoActionCreator.TEXT));
emitStoreChange();
break;
case TodoActionCreator.ACTION_GET_ALL:
emitStoreChange();
break;
}
}
@Override
StoreChangeEvent changeEvent() {
StoreChangeEvent storeChangeEvent = new StoreChangeEvent();
storeChangeEvent.value = TodoRepositories.getTodos();
return storeChangeEvent;
}
private void create(String text) {
TodoRepositories.getTodos().add(new Todo(new Random().nextInt(), text));
}
}
MainActivity
public class MainActivity extends AppCompatActivity implements Store.OnStoreChangeListener, View.OnClickListener{
private RecyclerView rvContent;
private EditText etTodo;
private Button btnAdd;
private ContentAdapter mContentAdapter;
private TodoActionCreator todoActionCreator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rvContent = (RecyclerView) findViewById(R.id.rvContent);
rvContent.setLayoutManager(new LinearLayoutManager(this));//這里用線性顯示 類似于listview
etTodo = (EditText) findViewById(R.id.etTodo);
btnAdd = (Button) findViewById(R.id.btnAdd);
btnAdd.setOnClickListener(this);
mContentAdapter = new ContentAdapter(new ArrayList<Todo>(),this);
rvContent.setAdapter(mContentAdapter);
todoActionCreator = TodoActionCreator.get(Dispatcher.get(this));
todoActionCreator.getAll();
}
@Override
public void OnStoreChange(Store.StoreChangeEvent storeChangeEvent) {
mContentAdapter.update((ArrayList<Todo>) storeChangeEvent.value);
mContentAdapter.notifyDataSetChanged(); }
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btnAdd:
String text = etTodo.getText().toString();
todoActionCreator.create(text);
etTodo.setText("");
break;
}
}}
代碼鏈接: http://pan.baidu.com/s/1c1oovss 密碼: 9jnk
VS MVC
我們可以拿MVC比較一下,理想中MVC如下:

但在使用過(guò)程,一不小心就增加了View和Model之間的交互,導(dǎo)致Model和View之間的錯(cuò)綜復(fù)雜,不利于維護(hù)和測(cè)試。


而Flux則可以維持?jǐn)?shù)據(jù)的單向性,如下:

總結(jié)
Flux優(yōu)點(diǎn)
- Improved data consistency 改善數(shù)據(jù)統(tǒng)一
- Easier to pinpoint root of bug 方便找到bug
- More meaningful unit tests 產(chǎn)生更多有意義的單元測(cè)試
Flux缺點(diǎn)
- Dispatcher 容易臃腫,復(fù)雜
- 代碼過(guò)于模板化
- 移植現(xiàn)有代碼比較困難
參考
原始地址: http://m.itdecent.cn/p/d6f9d2ee64a2,歡迎關(guān)注我的微博