《重构:改善既有代码的设计》中提到过很多重构方法,关于在对象之间搬移特性的方法有8种。本文介绍:
引入本地扩展 introduce local extension
- 名称:引入本地扩展 introduce local extension
- 概要:需要为服务类提供一些额外函数,但你无法修改这个类。建立一个新类,使它包含这些额外函数。让这个扩展品成为源类的子类或包装类。
- 动机:如果正在使用一个类,为你提供了需要的所有服务。而你想要增加新的服务,这个类却无法供应。你不得不在客户端编码,补足你要的那个函数。而这个函数本应该在提供服务的类中实现。增加的函数个数超过2个。
- 做法:
- 建立一个扩展类,将它作为原始类的子类或包装类
- 在扩展类中加入转型构造函数。转型构造函数是指“接受原对象作为参数”的构造函数。如果采用子类化方案,转型构造函数应该调用适当的超类构造函数。如果采用包装类方案,那么转型构造函数应该将它得到的传入参数以实例变量的形式保存起来,用作接受委托的原对象。
- 在扩展类中加入新特性。
- 根据需要,将原对象替换为扩展对象
- 将针对原始类定义的所有外加函数搬移到扩展类中。
- 代码演示
修改之前的代码:
///.h
#ifndef REFACTORMOVE_H
#define REFACTORMOVE_H
class Date
{
public:
Date(int year, int month, int day);
int GetYear();
int GetMonth();
int GetDay();
private:
int m_Year;
int m_Month;
int m_Day;
};
#endif // REFACTORMOVE_H
///.cpp
Date::Date(int year, int month, int day)
{
m_Year = year;
m_Month = month;
m_Day = day;
}
int Date::GetYear()
{
return m_Year;
}
int Date::GetMonth()
{
return m_Month;
}
int Date::GetDay()
{
return m_Day;
}
///main.cpp
Date date1(2019, 4, 18);
Date newStart = Date(date1.GetYear(), date1.GetMonth(), date1.GetDay() + 1);
修改之后的代码:
///.h
#ifndef REFACTORMOVE_H
#define REFACTORMOVE_H
class Date
{
public:
Date(int year, int month, int day);
int GetYear();
int GetMonth();
int GetDay();
private:
int m_Year;
int m_Month;
int m_Day;
};
//子类
class MfDateSub : public Date
{
public:
MfDateSub(int year, int month, int day);
MfDateSub(Date *pdate);
MfDateSub NextDay();
};
//包装类
class MfDateWrap
{
public:
MfDateWrap(int year, int month, int day);
MfDateWrap(Date *pdate);
//为原始类提供所有函数的委托
int GetYear();
int GetMonth();
int GetDay();
Date NextDay();
private:
Date *m_pOrigin;
};
#endif // REFACTORMOVE_H
///.cpp
Date::Date(int year, int month, int day)
{
m_Year = year;
m_Month = month;
m_Day = day;
}
int Date::GetYear()
{
return m_Year;
}
int Date::GetMonth()
{
return m_Month;
}
int Date::GetDay()
{
return m_Day;
}
MfDateSub::MfDateSub(int year, int month, int day):Date(year, month,day)
{
}
MfDateSub::MfDateSub(Date *pdate):Date(pdate->GetYear(), pdate->GetMonth(),pdate->GetDay())
{
}
MfDateSub MfDateSub::NextDay()
{
return MfDateSub(GetYear(),GetMonth(),GetDay() + 1);
}
MfDateWrap::MfDateWrap(int year, int month, int day)
{
m_pOrigin = new Date(year, month, day);
}
MfDateWrap::MfDateWrap(Date *pdate)
{
m_pOrigin = pdate;
}
int MfDateWrap::GetYear()
{
return m_pOrigin->GetYear();
}
int MfDateWrap::GetMonth()
{
return m_pOrigin->GetMonth();
}
int MfDateWrap::GetDay()
{
return m_pOrigin->GetDay();
}
Date MfDateWrap::NextDay()
{
return Date(GetYear(), GetMonth(), GetDay() + 1);
}
///main.cpp
Date date1(2019, 4, 18);
Date *newStart = new MfDateSub(&date1);
MfDateWrap newStart2 = MfDateWrap(&date1);
问题:对于包装类有个特殊问题:如何处理“接受原始类之实例为参数”的函数? 例如:bool after(Date date);
解决方案:由于无法改变原始类,所以只能使包装类上的after()函数可以接受包装类或原始类的对象。但原始类的afte()函数只能接受原始类对象,不接受包装类对象。
aWrapper.after(aDate); // OK
aWrapper.after(anotherWrapper);// OK
aDate.after(aWrapper); //not work