天天看點

利用單一職責原則、接口隔離原則和單例模式對代碼進行優化

待優化的代碼見上個部落格:https://blog.csdn.net/wangning13ji/article/details/85064184

本文針對Test4裡的MainActivity進行優化。

優化前:MainActivity.java

package com.test4.w00425655.test4;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        final TextView mTextview = (TextView) findViewById(R.id.textview);

        try {
            //擷取UID,驗證是否相同
            PackageManager pm = getPackageManager();
            ApplicationInfo ai = pm.getApplicationInfo("com.test4.w00425655.test4", 0);
            Toast.makeText(MainActivity.this, Integer.toString(ai.uid,10), Toast.LENGTH_SHORT).show();
            mTextview.setText(Integer.toString(ai.uid,10));
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }


        Context context = null;
        try {
            context = this.createPackageContext("com.test5.w00425655.test5",CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY);

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        final Context finalContext = context;
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                Class clazz = null;
                Object object = null;
                try {
                    //加載Test4的類和函數
                    clazz = finalContext.getClassLoader().loadClass("com.test5.w00425655.test5.MainActivity");
                    object = clazz.newInstance();
                    Method method = clazz.getDeclaredMethod("getString",String.class);
                    mTextview.setText((String)method.invoke(object,"cccccccccc"));
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }


                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {

            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
           

各位看官可以看到,優化前該Activity毫無設計模式和原則可言,是不是聞到了代碼腐朽的味道,看到這樣的代碼是不是沒有了繼續寫下去的勇氣啦。沒關系,接下來,我們将對它進行一次人生的洗禮,讓它的價值得到完美的升華。

我們會利用單一職責原則,把加載類和調用方法的函數抽離出來封裝一個類,該類隻負責動态加載類,不進行其他操作。接着還需要利用接口隔離原則,把該類抽象成一個接口,這樣,我們暴露給調用者的隻有接口,不會有具體的實作,看起來是不是更加清晰明了了呢。最後,這個類我們隻需要一個單例,不需要每次調用的時候都建立一個對象,節省了資源。下面就來看看最終的實作吧!duang~

抽象的接口類LoadClassService.java      
package com.test4.w00425655.test4;

import android.content.Context;

public interface LoadClassService {
    /*Test5提供給Test4的接口*/
    String getString(String str, Context context);
}
           

接口的實作LoadClassImpl.java

package com.test4.w00425655.test4;

import android.content.Context;
import android.content.pm.PackageManager;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static android.content.Context.CONTEXT_INCLUDE_CODE;

public class LoadClassImpl implements LoadClassService {
    private volatile static LoadClassService sLoadClass = null;
    private LoadClassImpl (){
    };
    public static LoadClassService getLoadClass (){
        if (null == sLoadClass) {
            synchronized (LoadClassImpl.class) {
                if (null == sLoadClass) {
                    sLoadClass = new LoadClassImpl();
                }
            }
        }
        return sLoadClass;
    }
    @Override
    public String getString (String str,Context context) {
        Class clazz = null;
        Object object = null;
        try {
            //加載Test4的類和函數
            clazz = getClazz("com.test5.w00425655.test5","com.test5.w00425655.test5.MainActivity",context);
            object = clazz.newInstance();
            Method method = clazz.getDeclaredMethod("getString",String.class);
            return (String)method.invoke(object,str);
        }  catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    private Class getClazz(String path, String className,Context context){

        Class clazz = null;
        try {
            //加載Test4的類
            clazz = context.getClassLoader().loadClass(className);
            return clazz;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}
           

MainActivity.java的調用:

package com.test4.w00425655.test4;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MainActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        final TextView mTextview = (TextView) findViewById(R.id.textview);

        try {
            //擷取UID,驗證是否相同
            PackageManager pm = getPackageManager();
            ApplicationInfo ai = pm.getApplicationInfo("com.test4.w00425655.test4", 0);
            Toast.makeText(MainActivity.this, Integer.toString(ai.uid,10), Toast.LENGTH_SHORT).show();
            mTextview.setText(Integer.toString(ai.uid,10));
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        Context context = null;
        try {
            context = this.createPackageContext("com.test5.w00425655.test5",CONTEXT_INCLUDE_CODE|Context.CONTEXT_IGNORE_SECURITY);

        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        final Context finalContext = context;
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LoadClassService loadClass = LoadClassImpl.getLoadClass();
                mTextview.setText(loadClass.getString("cccc", finalContext));


                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }



    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {

            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
           

這樣我們的優化就這麼簡單的完成了,是不是更加清晰明了了呢。真棒~