refactoring
リファクタリング
機能そのものの振る舞いは変化させず、ソースコードを整理する
メリット
- ソースコードを読みやすくなる
- 機能追加しやすくなる
- バグをみつけやすくする
不吉な匂い
ソースコードに以下のような特徴が見つかったら、リファクタリングをする余地がある
- if文,switch文が多い
- 同じような構文が登場する
- 双方向リンクがある
- クラス・メソッドが長い
- 意味のわからない変数がある
- 一時変数が邪魔
- 引数が多い
- if文内で正常系がわかりにくい
メソッドの抽出
長すぎるメソッドは汎用的な機能を抽出して、再利用性を高める
リファクタリング前
public void printLog(){
System.out.println("----------------------------");
System.out.println("ぶとうかのこうげき!");
System.out.println("スライムに16のダメージ!");
System.out.println("----------------------------");
System.out.println("ゆうしゃのこうげき!");
System.out.println("スライムに32のダメージ!");
System.out.println("----------------------------");
System.out.println("そうりょはバギクロスをとなえた!");
System.out.println("ドラキーAに64のダメージ!");
System.out.println("ドラキーBに64のダメージ!");
System.out.println("ドラキーCに64のダメージ!");
System.out.println("----------------------------");
}
リファクタリング後
public void printLog(){
printLine();
System.out.println("ぶとうかのこうげき!");
printDamage("スライム", 16);
printLine();
System.out.println("ゆうしゃのこうげき!");
printDamage("スライム", 32);
printLine();
System.out.println("そうりょはバギクロスをとなえた!");
printDamage("ドラキーA", 64);
printDamage("ドラキーB", 64);
printDamage("ドラキーC", 64);
printLine();
}
public void printLine(){
System.out.println("----------------------------");
}
public void printDamage(String name, int damage){
System.out.printf("%sに%dのダメージ!\n", name, dmage);
}
クラスの抽出
長すぎるクラスは役割を分担して、クラスの機能を明確にする
リファクタリング前
public class Player{
public void readBook(){}
public void writeBook(){}
public void buyItem(){}
public void saleItem(){}
}
リファクタリング後
public class Player{
public void book(){}
}
public class Book{
public void read(){}
public void write(){}
}
public class Item{
public void buy(){}
public void sale(){}
}
引数オブジェクトの導入
複数にわたる引数は順番などが複雑になるため、頻繁に一緒に受け渡しされる値はオブジェクトにまとめる
リファクタリング前
public calc(int x1,int y1,int w1,int h1, int x2,int y2,int w2,int h2){
}
リファクタリング後
public calc(Rectangle rect1, Rectangle rect2){
}
マジックナンバーの削除
プログラミングで使われる意味のない分類のためだけの数値を、マジックナンバーと呼ぶ。
ソースコード中に含まれる数値は単体では意味がわかりにくいため、シンボリック定数にして、意味がわかりやすいようにする
リファクタリング前
area = r * r * 3.14; total = price * 1.05;
リファクタリング後
static final float PI = 3.14; static final float SHOUHI_ZEI = 1.05; area = r * r * PI; total = price * SHOUHI_ZEI;
制御構文中のフラグを削除する
for文,if文で生まれたフラグをつくると、後にフラグを変化させない場合にわかりにくい
breakやreturnでループを抜けることで、その後の記述を読まずとも理解しやすくなる
リファクタリング前
public boolean isFlag(){
booblean flag = false;
for(){
if(j == 5){
flag = true;
} else {
}
}
return flag;
}
return flag;
リファクタリング後
public boolean isFlag(){
for(){
if(j == 5){
return true;
} else {
}
}
return false;
}
タイプコードの置き換え
リファクタリング後
enum ItemType{
BOOK, DVD, SOFTWARE;
}
class Purchase{
private final ItemType _itemType;
private final String _itemName;
public Purchase (ItemType itemType, String itemName){
_itemType = itemType;
_itemName = itemName;
}
public String buyArticle{
return _itemType+"の"+_itemName+"を買った\n";
}
}
State/Strategy
public class Logger {
private enum State {
STOPPED {
@Override public void start() {
System.out.println("** START LOGGING **");
}
@Override public void stop() {
/* Do nothing */
}
@Override public void log(String info) {
System.out.println("Ignoring: " + info);
}
},
LOGGING {
@Override public void start() {
/* Do nothing */
}
@Override public void stop() {
System.out.println("** STOP LOGGING **");
}
@Override public void log(String info) {
System.out.println("Logging: " + info);
}
};
public abstract void start();
public abstract void stop();
public abstract void log(String info);
}
private State _state;
public Logger() {
setState(State.STOPPED);
}
public void setState(State state) {
_state = state;
}
public void start() {
_state.start();
setState(State.LOGGING);
}
public void stop() {
_state.stop();
setState(State.STOPPED);
}
public void log(String info) {
_state.log(info);
}
}
public class Main {
public static void main(String[] args) {
Logger logger = new Logger();
logger.log("information #1");
logger.start();
logger.log("information #2");
logger.start();
logger.log("information #3");
logger.stop();
logger.log("information #4");
logger.stop();
logger.log("information #5");
}
}
アサーション
「この時点でこの変数はこうなっているはず」という前提を記述することで、自動チェックを行い、バグを発見しやすくする
アサーションの実行
java -ea Main
リファクタリング後
sq = w * w;
assert isAbsolute(sq);
private isAbsolute(int sq){
if(sq >= 0){
return true;
}
return false;
}
VideoGames|DS
VideoGames|PSP
VideoGames|PlayStation3
VideoGames|XBOX
VideoGames|任天堂
VideoGames|エニックス

