程式碼重構——妙用Android Studio
阿新 • • 發佈:2019-02-04
Android Studio是基於優秀的ide的,ide提供了豐富的功能,很方便的對程式碼進行重構,下圖是我的Android Studio Refactor選單,部分快捷鍵與預設快捷鍵不同是因為方便而修改的。
如何使用
滑鼠游標選中或者放在程式碼上,按下快捷鍵就可以彈出當前程式碼可以使用的功能。
如下所示:
- ChangeSignature,改變函式簽名,可以修改函式的名字,引數的順序,引數的名字。
Before:
// 改變簽名 void testChangeSignature(int second, int first) { System.out.println(first + "->" + second); }
After:
// 改變簽名
void testChangeSignature(int one, int two) {
System.out.println(one + "->" + two);
}
修改前引數依次是second、first,修改是one、two。
- 修改匿名類為內部類
Before:
// 匿名類改成內部類
void testConvertAnonymousToInner() {
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("onClick");
}
};
}
Gif:
After:
// 匿名類改成內部類
void testConvertAnonymousToInner() {
View.OnClickListener clickListener = new Abc123();
}
private static class Abc123 implements View.OnClickListener {
@Override
public void onClick(View v) {
System.out.println("onClick");
}
}
- Copy,複製一個類
Before:
// 複製一個類
void testCopy() {
new FirstClass();
}
public class FirstClass implements Serializable {
public String first;
@Override
public String toString() {
return "FirstClass{" +
"first='" + first + '\'' +
'}';
}
}
Gif:
After:
public class SecondClass implements Serializable {
public String first;
@Override
public String toString() {
return "SecondClass{" +
"first='" + first + '\'' +
'}';
}
}
- InvertBoolean,重構Boolean
Before:
// 重構Boolean
void testInvertBoolean() {
System.out.println(checkPaswd(null));
System.out.println(checkPaswd(""));
System.out.println(checkPaswd("admin"));
}
boolean checkPaswd(String passwd) {
if (passwd != null && passwd.length() != 0) {
return true;
}
return false;
}
Gif:
After:
// 重構Boolean
void testInvertBoolean() {
System.out.println(checkPaswd(null));
System.out.println(checkPaswd(""));
System.out.println(checkPaswd("admin"));
}
boolean checkPaswd(String passwd) {
return passwd != null && passwd.length() != 0;
}
- ReplaceConstructorWithBuilder,構造方法變成builder
還在羨慕Picasso,Fresco人性化呼叫方式嗎?很簡單,通過這個功能就可以快速生成程式碼
Before:
public class MyAlertDialog {
private String title;
private String message;
private String okButton;
private String cancelButton;
public MyAlertDialog(String title, String message, String okButton, String cancelButton) {
this.title = title;
this.message = message;
this.okButton = okButton;
this.cancelButton = cancelButton;
}
}
// 構造方法變成builder
void testReplaceConstructorWithBuilder() {
new MyAlertDialog("title", "message", "ok", "cancel").show();
}
Gif:
After:
// 構造方法變成builder
void testReplaceConstructorWithBuilder() {
new MyAlertDialog.Builder()
.setTitle("title")
.setMessage("message")
.setOkButton("ok")
.setCancelButton("cancel")
.createMyAlertDialog()
.show();
}
public static class Builder {
private String title;
private String message;
private String okButton;
private String cancelButton;
public Builder setTitle(String title) {
this.title = title;
return this;
}
public Builder setMessage(String message) {
this.message = message;
return this;
}
public Builder setOkButton(String okButton) {
this.okButton = okButton;
return this;
}
public Builder setCancelButton(String cancelButton) {
this.cancelButton = cancelButton;
return this;
}
public MyAlertDialog createMyAlertDialog() {
return new MyAlertDialog(title, message, okButton, cancelButton);
}
}
- ReplaceConstructorWithFactory,構造方法變成工程方法
Before:
// 構造方法變成工程方法
void testReplaceConstructorWithFactory() {
new MyAlertDialog("title", "message", "ok", "cancel").show();
}
- 1
- 2
- 3
- 4
Gif:
After:
// 構造方法變成工程方法
void testReplaceConstructorWithFactory() {
MyAlertDialog.newInstance("title", "message", "ok", "cancel")
.show();
}
public class MyAlertDialog {
private MyAlertDialog(String title, String message, String okButton, String cancelButton) {
this.title = title;
this.message = message;
this.okButton = okButton;
this.cancelButton = cancelButton;
}
public static MyAlertDialog newInstance(String title, String message, String okButton, String cancelButton) {
return new MyAlertDialog(title, message, okButton, cancelButton);
}
}
通過上面程式碼發現,如果構造方法變成了工廠方式,那麼它的構造引數是private的,這樣呼叫者只能通過工廠方式來生成物件。
程式碼抽取
- ExtractParameterObject,抽取若干引數成一個類
這個比較使用,有時候一個方法引數太多,可以把這些引數合併成一個類。
Before:
// 抽取若干引數成一個類
void testExtractParameterObject() {
print(100, 200);
}
// widht,height --> Size Class
void print(int width, int height) {
System.out.println("width = " + width + ", height = " + height);
}
Gif:
After:
// 抽取若干引數成一個類
void testExtractParameterObject() {
print(new Size(100, 200));
}
// widht,height --> Size Class
void print(Size size) {
System.out.println("width = " + size.getWidth() + ", height = " + size.getHeight());
}
public class Size {
private final int width;
private final int height;
public Size(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
- ExtractSuperclass,抽取到父類
Before:
// 抽取到父類
void testExtractSuperclass() {
sendEvent("login_success");
}
public void sendEvent(Object event) {
// EventBus.getDefault().send(event);
}
Gif:
After:
public class BaseExtractDemo {
public void sendEvent(Object event) {
// EventBus.getDefault().send(event);
}
}
public class ExtractDemo extends BaseExtractDemo {
// 抽取到父類
void testExtractSuperclass() {
sendEvent("login_success");
}
}
綜合示例
通過一個示例演示怎麼樣重構程式碼,示例是一個Activity裡面有個RecyclerView,然後重構程式碼,演示怎麼樣分離Adapter,ViewHolder等。
Before:
public class StartActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
final List<String> data = new ArrayList<>();
for (int i = 0; i < 100; i++) {
data.add("Text " + (i + 1));
}
recyclerView.setAdapter(new RecyclerView.Adapter<MyViewHolder>() {
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return new MyViewHolder(layoutInflater.inflate(android.R.layout.simple_list_item_1, parent, false));
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.bind(data.get(position));
}
@Override
public int getItemCount() {
return data.size();
}
});
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView textView;
public MyViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(android.R.id.text1);
}
void bind(String text) {
textView.setText(text);
}
}
}
Gif:
After:
public class StartActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<String> data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
initData();
initView();
}
private void initData() {
data = new ArrayList<>();
for (int i = 0; i < 100; i++) {
data.add("Text " + (i + 1));
}
}
private void initView() {
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(new MyViewHolderAdapter(data));
}
}
class MyViewHolderAdapter extends RecyclerView.Adapter<MyViewHolder> {
private List<String> data;
public MyViewHolderAdapter(List<String> data) {
this.data = data;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return MyViewHolder.newInstance(parent);
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.bind(data.get(position));
}
@Override
public int getItemCount() {
return data.size();
}
}
class MyViewHolder extends RecyclerView.ViewHolder {
public static final int LAYOUT_ID = android.R.layout.simple_list_item_1;
@NonNull
static MyViewHolder newInstance(ViewGroup parent) {
Context context = parent.getContext();
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return new MyViewHolder(layoutInflater.inflate(LAYOUT_ID, parent, false));
}
TextView textView;
public MyViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(android.R.id.text1);
}
void bind(String text) {
textView.setText(text);
}
}