第1章 重构,第一个案例(3):运用多态取代switch
3. 运用多态取代与价格相关的条件逻辑
3.1 switch和“常客积分”代码的再次搬迁
(1)switch:最好不要在另一个对象的属性上运用switch语句
switch(getMovie().getPriceCode()) //在movie对象的priceCode属性上运用switch
{ //这意味着可以将getCharge函数从Rental类移动到Movie类去
//选择在Movie类中封装计算费用功能,还有一个
//原因,就是可以控制因影片类型变化导致的计算
//方式变化,从而对其它对象产生影响。
…
}
(2)常客积分:getFrequentRenterPoints函数的再次搬迁。用跟处理getCharge相同的手法处理常客积分,将因影片类型变化而变化的所有东西都放到Movie类中去处理。Rental类中只需调用Movie相应的方法即可。
【实例分析】影片出租1.3.1

//第1章:重构,第1个案例
//场景:影片出租,计算每一位顾客的消费金额
/*
说明:
1. 影片分3类:普通片、儿童片和新片。
2. 每种影片计算租金的方式。
A.普通片:基本租金为2元,超过2天的部分每天加1.5元
B.新片:租期*3
C.儿童片:基本租金为1.5元,超过3天的部分每天加1.5元
3. 积分的计算:每借1片,积分加1,如果是新片且租期1天以上的额外赠送1分。
*/
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std; //影片类
class Movie
{
private:
string title; //片名
int priceCode; //价格 public:
enum MovieType{
REGULAR = , //普通片
NEW_RELEASE, //新片
CHILDRENS //儿童片
}; Movie(string title, int priceCode)
{
this->title = title;
this->priceCode = priceCode;
} string getTitle(){return title;}
void setTitle(string value)
{
title = value;
} int getPriceCode(){return priceCode;}
void setPriceCode(int value)
{
this->priceCode = value;
} //将原来Rental类中的getCharge移到该类中,并将租期作为参数传入
//搬到这里来的原因是
//1.switch语句中getPriceCode为本类对象的属性
//2.封装影片类型的变化导致计算方式变化于该类中,从而降低对其他类的影响
double getCharge(int daysRented)
{
double result = ;//相当于statement中的thisamount; switch(getPriceCode())
{
case Movie::REGULAR:
result += ; //普通片基本租金为2元
if(daysRented > ) //超过2天的每天加1.5元
result +=(daysRented - ) * 1.5;
break;
case Movie::NEW_RELEASE:
result += daysRented * ; //新片的租金
break;
case Movie::CHILDRENS:
result += 1.5; //儿童片基本租金为1.5元
if(daysRented > ) //超过3天的每天加1.5元
result +=(daysRented - ) * 1.5;
break;
} return result;
} //将原Rental类中常客积分搬到该类中
//原因是常客积分的计费方式与影片类型有关,也是为了控制当
//影片类型变化时,由于计算方式变化对其他类的影响
int getFrequentRenterPoints(int daysRented)
{
//如果是新片且租期超过1天以上,则额外送1分积分
if ((getPriceCode() == Movie::NEW_RELEASE) &&
daysRented > ) return ;
else return ;
}
}; //租赁类(表示某个顾客租了一部影片)
class Rental
{
private:
Movie& movie; //所租的影片
int daysRented; //租期
public:
Rental(Movie& movie, int daysRented):movie(movie)
{
this->daysRented = daysRented;
} int getDaysRented(){return daysRented;} Movie& getMovie()
{
return movie;
} double getCharge()
{
return movie.getCharge(daysRented);
} //将原Customer类的statement中计算常客积分的代码移到Rental类
int getFrequentRenterPoints()
{
return movie.getFrequentRenterPoints(daysRented);
}
}; //顾客类(用来表示顾客)
class Customer
{
private:
string name; //顾客姓名
vector<Rental*> rentals; //每个租赁记录 //获得总消费
double getTotalCharge()
{
double result = ;
vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); result += each.getCharge(); ++iter;
}
return result;
} //获得总积分
int getTotalFrequentRenterPointers()
{
int result = ; vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); result += each.getFrequentRenterPoints(); ++iter;
} return result;
} void cleanUp()
{
vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
delete(*iter);
++iter;
}
rentals.clear();
} template <typename T>
string numToString(T num)
{
stringstream ss;
ss << num;
return ss.str();
} public:
Customer(string name)
{
this->name = name;
} void addRental(Rental* value)
{
rentals.push_back(value);
} string getName(){return name;} //statement(报表),生成租赁的详单
string statement()
{
string ret = "Rental Record for " + name + "\n"; vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); //显示每个租赁记录 ret += "\t" + each.getMovie().getTitle() + "\t" +
numToString(each.getCharge())+ "\n"; ++iter;
} //增加页脚注释
ret += "Amount owed is " + numToString(getTotalCharge()) + "\n";//用getTotalCharge代替totalAmount
ret += "You earned " + numToString(getTotalFrequentRenterPointers()) +"\n"; return ret;
} ~Customer()
{
cleanUp();
}
}; void init(Customer& customer)
{
Movie* mv = new Movie("倚天屠龙记",Movie::REGULAR);
Rental* rt = new Rental(*mv, );
customer.addRental(rt); mv = new Movie("新水浒传",Movie::NEW_RELEASE);
rt = new Rental(*mv, );
customer.addRental(rt); mv = new Movie("喜羊羊与灰太狼",Movie::CHILDRENS);
rt = new Rental(*mv, );
customer.addRental(rt);
} int main()
{
Customer customer("SantaClaus");
init(customer); cout << customer.statement() <<endl; return ;
}
/*输出结果
Rental Record for SantaClaus
倚天屠龙记 2
新水浒传 9
喜羊羊与灰太狼 4.5
Amount owed is 15.5
You earned 4
*/
3.2 运用子类取代类型码

(1)使用继承子类的方式,可以利用多态来取代switch语句。
(2)重构的步骤
①使用“自我封装字段”的方法将类型码通过get/set函数封装起来(如Movie类的getPriceCode函数)。如果类型码被传递给构造函数,就需要将构造函数换成工厂方法(如createMovie函数)
②以类型码的宿主类为基类,为类型码的每一个数值建立一个相应的子类。在每个子类中覆写类型码的取值函数,使其返回相应的类型码值。(见Movie子类getPriceCode)
③从父类中删除保存类型码的字段(即旧Movie类的priceCode字段),将类型码访问函数声明为抽象函数(如Movie中的getPriceCode)
④使用pushDownMethod/Field方法将与特定类型码相关的函数推到子类来实现(如本例中的getCharge函数)
(3)缺点:
①对于某个具体对象,在其生命周期中其状态(或本例中类型码)是不可改变的(如代表Movie子类型的priceCode是不能更改的),所以当创建了一部影片出来以后,就不能修改其类型了。如,现在某影片是“新片”类型,但即使随着时间的推移,也不能更改为“普通片”或“儿童片”了。
②我们总是在避免使用switch语句,虽然利用了多态将各个case语句的代码分解到相应的子类中去实现。但在Movie类的createMovie函数中仍然要出现switch语句。幸运的是,仅此一处用到switch,并且只用于决定创建何种对象而没有其他的业务逻辑,所以这样的switch语句是可以接受的。
【实例分析】影片出租1.3.2
//types.h
#include <vector>
#include <string>
#include <sstream>
using namespace std; //影片类
class Movie
{
private:
string title; //片名
//int priceCode; //价格,注意,这里被注释了 public:
enum MovieType{
REGULAR = , //普通片
NEW_RELEASE, //新片
CHILDRENS //儿童片
}; Movie(string title); static Movie* createMovie(string title, int priceCode); string getTitle();
void setTitle(string value); //类型码的“自我封装”(提供取值函数)
virtual int getPriceCode() = ; //将原来Rental类中的getCharge移到该类中,并将租期作为参数传入
//搬到这里来的原因是
//1.switch语句中getPriceCode为本类对象的属性
//2.封装影片类型的变化导致计算方式变化于该类中,从而降低对其他类的影响
virtual double getCharge(int daysRented); int getFrequentRenterPoints(int daysRented);
}; //普通片:用子类取代类型码
class RegularMovie: public Movie
{
public:
RegularMovie(string title);
int getPriceCode();
double getCharge(int daysRented);
}; //儿童片:
class ChildrensMovie: public Movie
{ public:
ChildrensMovie(string title);
int getPriceCode();
double getCharge(int daysRented);
}; //新片
class ReleaseMovie: public Movie
{
public:
ReleaseMovie(string title);
int getPriceCode();
double getCharge(int daysRented);
}; //租赁类(表示某个顾客租了一部影片)
class Rental
{
private:
Movie& movie; //所租的影片
int daysRented; //租期
public:
Rental(Movie& movie, int daysRented); int getDaysRented(); Movie& getMovie(); double getCharge(); //将原Customer类的statement中计算常客积分的代码移到Rental类
int getFrequentRenterPoints();
}; //顾客类(用来表示顾客)
class Customer
{
private:
string name; //顾客姓名
vector<Rental*> rentals; //每个租赁记录 //获得总消费
double getTotalCharge(); //获得总积分
int getTotalFrequentRenterPointers(); void cleanUp(); template <typename T>
string numToString(T num)
{
stringstream ss;
ss << num;
return ss.str();
} public:
Customer(string name); void addRental(Rental* value);
string getName(); //statement(报表),生成租赁的详单
string statement(); ~Customer();
};
//main.cpp
//第1章:重构,第1个案例
//场景:影片出租,计算每一位顾客的消费金额
/*
说明:
1. 影片分3类:普通片、儿童片和新片。
2. 每种影片计算租金的方式。
A.普通片:基本租金为2元,超过2天的部分每天加1.5元
B.新片:租期*3
C.儿童片:基本租金为1.5元,超过3天的部分每天加1.5元
3. 积分的计算:每借1片,积分加1,如果是新片且租期1天以上的额外赠送1分。
*/
#include <iostream>
#include "types.h"
using namespace std; //*********************************************影片类*************************************
Movie::Movie(string title)
{
this->title = title;
}
//提供创建子类实例的静态函数(也可以使用工厂方法)
Movie* Movie::createMovie(string title, int priceCode)
{
Movie* ret = NULL;
//利用子类替代switch的分支。我们总是在避免使用switch语句。但这里
//只有一处用到switch,并且只用于决定创建何种对象而没有其他的业务逻辑
//所以这样的switch语句是可以接受的。
switch(priceCode)
{
case Movie::REGULAR:
ret = new RegularMovie(title);
break;
case Movie::CHILDRENS:
ret = new ChildrensMovie(title);
break;
case Movie::NEW_RELEASE:
ret = new ReleaseMovie(title);
break;
} return ret;
} string Movie::getTitle()
{
return title;
} void Movie::setTitle(string value)
{
title = value;
} double Movie::getCharge(int daysRented)
{
return Movie::REGULAR;
} //将原Rental类中常客积分搬到该类中
//原因是常客积分的计费方式与影片类型有关,也是为了控制当
//影片类型变化时,由于计算方式变化对其他类的影响
int Movie::getFrequentRenterPoints(int daysRented)
{
//如果是新片且租期超过1天以上,则额外送1分积分
if ((getPriceCode() == Movie::NEW_RELEASE) &&
daysRented > ) return ;
else return ;
} //普通片:用子类取代类型码
RegularMovie::RegularMovie(string title):Movie(title)
{
} int RegularMovie::getPriceCode()
{
return Movie::REGULAR;
} //使用pushDownMethod(Field)方法将与特定类型码相关的函数推到子类来实现
double RegularMovie::getCharge(int daysRented)
{
double result = ; if(daysRented > ) //超过2天的每天加1.5元
result +=(daysRented - ) * 1.5; return result;
} //儿童片
ChildrensMovie::ChildrensMovie(string title):Movie(title)
{
} int ChildrensMovie::getPriceCode()
{
return Movie::CHILDRENS;
} //使用pushDownMethod(Field)方法将与特定类型码相关的函数推到子类来实现
double ChildrensMovie::getCharge(int daysRented)
{
double result = 1.5;//儿童片基本租金为1.5元 if(daysRented > ) //超过3天的每天加1.5元
result +=(daysRented - ) * 1.5; return result;
} //新片
ReleaseMovie::ReleaseMovie(string title):Movie(title)
{
} int ReleaseMovie::getPriceCode()
{
return Movie::NEW_RELEASE;
}
//使用pushDownMethod(Field)方法将与特定类型码相关的函数推到子类来实现
double ReleaseMovie::getCharge(int daysRented)
{
return daysRented * ; //新片的租金
} //********************************租赁类(表示某个顾客租了一部影片)**********************************
Rental::Rental(Movie& movie, int daysRented):movie(movie)
{
this->daysRented = daysRented;
} int Rental::getDaysRented(){return daysRented;} Movie& Rental::getMovie()
{
return movie;
} double Rental::getCharge()
{
return movie.getCharge(daysRented);
} //将原Customer类的statement中计算常客积分的代码移到Rental类
int Rental::getFrequentRenterPoints()
{
return movie.getFrequentRenterPoints(daysRented);
} //*********************************顾客类(用来表示顾客)*************************************
//获得总消费
double Customer::getTotalCharge()
{
double result = ;
vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); result += each.getCharge(); ++iter;
}
return result;
} //获得总积分
int Customer::getTotalFrequentRenterPointers()
{
int result = ; vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); result += each.getFrequentRenterPoints(); ++iter;
} return result;
} void Customer::cleanUp()
{
vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
delete(*iter);
++iter;
}
rentals.clear();
} Customer::Customer(string name)
{
this->name = name;
} void Customer::addRental(Rental* value)
{
rentals.push_back(value);
} string Customer::getName(){return name;} //statement(报表),生成租赁的详单
string Customer::statement()
{
string ret = "Rental Record for " + name + "\n"; vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); //显示每个租赁记录 ret += "\t" + each.getMovie().getTitle() + "\t" +
numToString(each.getCharge())+ "\n"; ++iter;
} //增加页脚注释
ret += "Amount owed is " + numToString(getTotalCharge()) + "\n";//用getTotalCharge代替totalAmount
ret += "You earned " + numToString(getTotalFrequentRenterPointers()) +"\n"; return ret;
} Customer::~Customer()
{
cleanUp();
} //************************************************初始化数据******************************************** void init(Customer& customer)
{
Movie* mv = Movie::createMovie("倚天屠龙记",Movie::REGULAR);
Rental* rt = new Rental(*mv, );
customer.addRental(rt); mv = Movie::createMovie("新水浒传",Movie::NEW_RELEASE);
rt = new Rental(*mv, );
customer.addRental(rt); mv = Movie::createMovie("喜羊羊与灰太狼",Movie::CHILDRENS);
rt = new Rental(*mv, );
customer.addRental(rt);
} int main()
{
Customer customer("SantaClaus");
init(customer); cout << customer.statement() <<endl; return ;
}
/*输出结果
Rental Record for SantaClaus
倚天屠龙记 2
新水浒传 9
喜羊羊与灰太狼 4.5
Amount owed is 15.5
You earned 4
*/
3.3 以state/strategy取代类型码
(1)对象的状态在生命周期内可以变化,可以选用state模式(本例中有3种状态:REGULAR、CHILDREN、NEW_RELEASE)。而前一个例子中,对象与其状态是紧耦合的,本例利用state模式来组合对象与其状态,达到松耦合的目的。
(2)重构的步骤
①使用SelfEncapsulate Field来封装类型码,确保任何时候都通过取值和设值函数访问类型代码。
②新建一个Price类,并在其中提供类型相关的函数。如Price类中加入一个纯虚函数getPriceCode,并在所有子类中加上对应的具体函数。
③为Price添加子类,每个子类对应一种类型码。并提供getPriceCode的具体实现。
④利用pushDownMethod/Field方法将与类型码相关的函数从Price类推到子类去实现。(如getCharge、getFrequentRenterPoints函数)
⑤在Movie类中保存一个Price的引用,用来保存新建的状态对象。同时调整Movie中各个与类型码相关的函数,将动作转发到状态对象上(如Movie的getCharge函数)。
(3)引入state模式的好处
①如果要修改任何与价格有关的行为只需修改相应的子类即可。添加新的定价标准也只需扩展新的Price子类即可。
②修改影片分类结构或是改变费用的计算规则、改变常客积分计算规则都很容易。
【实例分析】影片出租1.3.3

//types.h
#include <vector>
#include <string>
#include <sstream>
using namespace std; enum MovieType{
REGULAR = , //普通片
NEW_RELEASE, //新片
CHILDRENS //儿童片
}; //price类
class Price
{
public:
virtual int getPriceCode() = ;
virtual double getCharge(int daysRented) = ;
virtual int getFrequentRenterPoints(int daysRented){return ;}
virtual ~Price(){}
}; //普通:
class RegularPrice: public Price
{
public:
int getPriceCode();
double getCharge(int daysRented);
}; //儿童片:
class ChildrensPrice: public Price
{
public:
int getPriceCode();
double getCharge(int daysRented);
}; //新片
class ReleasePrice: public Price
{
public:
int getPriceCode();
double getCharge(int daysRented);
int getFrequentRenterPoints(int daysRented);
}; //影片类
class Movie
{
private:
string title; //片名
Price* price; //价格类 public:
Movie(string title, int priceCode);
~Movie(); string getTitle();
void setTitle(string value); int getPriceCode();
void setPriceCode(int priceCode); double getCharge(int daysRented); int getFrequentRenterPoints(int daysRented);
}; //租赁类(表示某个顾客租了一部影片)
class Rental
{
private:
Movie& movie; //所租的影片
int daysRented; //租期
public:
Rental(Movie& movie, int daysRented); int getDaysRented(); Movie& getMovie(); double getCharge(); //将原Customer类的statement中计算常客积分的代码移到Rental类
int getFrequentRenterPoints();
}; //顾客类(用来表示顾客)
class Customer
{
private:
string name; //顾客姓名
vector<Rental*> rentals; //每个租赁记录 //获得总消费
double getTotalCharge(); //获得总积分
int getTotalFrequentRenterPointers(); void cleanUp(); template <typename T>
string numToString(T num)
{
stringstream ss;
ss << num;
return ss.str();
} public:
Customer(string name); void addRental(Rental* value);
string getName(); //statement(报表),生成租赁的详单
string statement(); ~Customer();
};
//main.cpp
//第1章:重构,第1个案例
//场景:影片出租,计算每一位顾客的消费金额
/*
说明:
1. 影片分3类:普通片、儿童片和新片。
2. 每种影片计算租金的方式。
A.普通片:基本租金为2元,超过2天的部分每天加1.5元
B.新片:租期*3
C.儿童片:基本租金为1.5元,超过3天的部分每天加1.5元
3. 积分的计算:每借1片,积分加1,如果是新片且租期1天以上的额外赠送1分。
*/
#include <iostream>
#include "types.h"
using namespace std; //*******************************************价格类**************************************
//普通片:用子类取代类型码
int RegularPrice::getPriceCode()
{
return REGULAR;
} //使用pushDownMethod(Field)方法将与特定类型码相关的函数推到子类来实现
double RegularPrice::getCharge(int daysRented)
{
double result = ; if(daysRented > ) //超过2天的每天加1.5元
result +=(daysRented - ) * 1.5; return result;
} //儿童片
int ChildrensPrice::getPriceCode()
{
return CHILDRENS;
} //使用pushDownMethod(Field)方法将与特定类型码相关的函数推到子类来实现
double ChildrensPrice::getCharge(int daysRented)
{
double result = 1.5;//儿童片基本租金为1.5元 if(daysRented > ) //超过3天的每天加1.5元
result +=(daysRented - ) * 1.5; return result;
} //新片
int ReleasePrice::getPriceCode()
{
return NEW_RELEASE;
}
//使用pushDownMethod(Field)方法将与特定类型码相关的函数推到子类来实现
double ReleasePrice::getCharge(int daysRented)
{
return daysRented * ; //新片的租金
} int ReleasePrice::getFrequentRenterPoints(int daysRented)
{
return (daysRented > ) ? : ;
} //*********************************************影片类*************************************
Movie::Movie(string title, int priceCode):price(NULL)
{
this->title = title;
setPriceCode(priceCode);
} string Movie::getTitle()
{
return title;
} void Movie::setTitle(string value)
{
title = value;
} int Movie::getPriceCode()
{
return price->getPriceCode();
} void Movie::setPriceCode(int priceCode)
{
if (price != NULL)
delete price; switch(priceCode)
{
case REGULAR:
price = new RegularPrice();
break;
case CHILDRENS:
price = new ChildrensPrice();
break;
case NEW_RELEASE:
price = new ReleasePrice();
break;
}
} double Movie::getCharge(int daysRented)
{
double ret = ;
if (price != NULL)
ret = price->getCharge(daysRented);
return ret;
} int Movie::getFrequentRenterPoints(int daysRented)
{
return price->getFrequentRenterPoints(daysRented);
} Movie::~Movie()
{
delete price;
} //********************************租赁类(表示某个顾客租了一部影片)**********************************
Rental::Rental(Movie& movie, int daysRented):movie(movie)
{
this->daysRented = daysRented;
} int Rental::getDaysRented(){return daysRented;} Movie& Rental::getMovie()
{
return movie;
} double Rental::getCharge()
{
return movie.getCharge(daysRented);
} //将原Customer类的statement中计算常客积分的代码移到Rental类
int Rental::getFrequentRenterPoints()
{
return movie.getFrequentRenterPoints(daysRented);
} //*********************************顾客类(用来表示顾客)*************************************
//获得总消费
double Customer::getTotalCharge()
{
double result = ;
vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); result += each.getCharge(); ++iter;
}
return result;
} //获得总积分
int Customer::getTotalFrequentRenterPointers()
{
int result = ; vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); result += each.getFrequentRenterPoints(); ++iter;
} return result;
} void Customer::cleanUp()
{
vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
delete(*iter);
++iter;
}
rentals.clear();
} Customer::Customer(string name)
{
this->name = name;
} void Customer::addRental(Rental* value)
{
rentals.push_back(value);
} string Customer::getName(){return name;} //statement(报表),生成租赁的详单
string Customer::statement()
{
string ret = "Rental Record for " + name + "\n"; vector<Rental*>::iterator iter = rentals.begin();
while( iter != rentals.end())
{
Rental& each = *(*iter); //显示每个租赁记录 ret += "\t" + each.getMovie().getTitle() + "\t" +
numToString(each.getCharge())+ "\n"; ++iter;
} //增加页脚注释
ret += "Amount owed is " + numToString(getTotalCharge()) + "\n";//用getTotalCharge代替totalAmount
ret += "You earned " + numToString(getTotalFrequentRenterPointers()) +"\n"; return ret;
} Customer::~Customer()
{
cleanUp();
} //************************************************初始化数据******************************************** void init(Customer& customer)
{
Movie* mv = new Movie("倚天屠龙记", REGULAR); mv->setPriceCode(NEW_RELEASE); //重新改变影片的类型为NEW_RELEASE
//这在上个例子是不可能的! Rental* rt = new Rental(*mv, );
customer.addRental(rt); mv = new Movie("新水浒传", NEW_RELEASE);
rt = new Rental(*mv, );
customer.addRental(rt); mv = new Movie("喜羊羊与灰太狼", CHILDRENS);
rt = new Rental(*mv, );
customer.addRental(rt);
} int main()
{
Customer customer("SantaClaus");
init(customer); cout << customer.statement() <<endl; return ;
}
/*输出结果
Rental Record for SantaClaus
倚天屠龙记 6
新水浒传 9
喜羊羊与灰太狼 4.5
Amount owed is 19.5
You earned 5
*/
第1章 重构,第一个案例(3):运用多态取代switch的更多相关文章
- ruby代码重构第一课
(文章是从我的个人主页上粘贴过来的, 大家也可以访问我的主页 www.iwangzheng.com) 新手写代码的时候往往会出现很多重复的代码没有提取出来,大师高瞻远瞩总能提点很多有意义的改进,今天重 ...
- 学习ExtjsForVs(第一个案例HelloWord)
第一个案例-Hello Word 1.本次练习以ext-4.0.7为例,首先从网上下载ext包. 2.打开包后将里面的三个文件或文件夹拷贝到项目中. resource文件夹 bootstrap.js ...
- spring boot实战(第一篇)第一个案例
版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] spring boot实战(第一篇)第一个案例 前言 写在前面的话 一直想将spring boot相关内容写成一个系列的 ...
- 第4章 TCP/IP通信案例:访问Internet上的Web服务器
第4章 TCP/IP通信案例:访问Internet上的Web服务器 4.2 部署代理服务器 书中为了演示访问Internet上的Web服务器的全过程,使用了squid代理服务器程序模拟了一个代理服务器 ...
- (转)编写Spring的第一个案例并测试Spring的开发环境
http://blog.csdn.net/yerenyuan_pku/article/details/52832145 Spring4.2.5的开发环境搭建好了之后,我们来编写Spring的第一个案例 ...
- javascript进阶教程第三章--匿名和闭包--案例实战
javascript进阶教程第三章--匿名和闭包--案例实战 一.学习任务 通过几个小练习回顾学过的知识点 二.实例 练习1: 实例描述:打开页面后规定时间内弹出一个新窗口,新窗口指定时间后自动关闭. ...
- Java生鲜电商平台-一次代码重构的实战案例
Java生鲜电商平台-一次代码重构的实战案例 说明,Java开源生鲜电商平台-一次代码重构的实战案例,根据实际的例子,分析出重构与抽象,使代码更加的健壮与高效. 1.业务说明 系统原先已有登录功能,我 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十五章:第一人称摄像机和动态索引
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十五章:第一人称摄像机和动态索引 代码工程地址: https://g ...
- 第1章 重构,第一个案例(2):分解并重组statement函数
2. 分解并重组statement (1)提炼switch语句到独立函数(amountFor)和注意事项. ①先找出函数内的局部变量和参数:each和thisAmount,前者在switch语句内未被 ...
随机推荐
- 数三角形 bzoj 1201
数三角形(1s 128MB)triangle [题目描述] 小苏看到一个这样的等边三角形:该等边三角形每边的长度为n且被分成n等份,于是每条边就有n-1个等分点.而整个三角形被连接两个不同边的等分点且 ...
- 初识Java
Java是一种简单的.面向对象的.分布式的.解释的.安全的.可移植的.性能优异的多线程语言.它以极强的安全性.平台无关性.硬件结构无关性.语言简洁.面向对象的特点,在网络编程语言中占据了无可比拟的优势 ...
- java Byte[] to String(hex)
1. 字节数组转换成16进制字符展示 2.代码 package com.goodfan; public class ByteArrayToString { private static char[] ...
- python之消息队列
引言 你是否遇到过两个(多个)系统间需要通过定时任务来同步某些数据?你是否在为异构系统的不同进程间相互调用.通讯的问题而苦恼.挣扎?如果是,那么恭喜你,消息服务让你可以很轻松地解决这些问题.消息服务擅 ...
- SharedPreferences漏洞, 无法避免,所以不要在里面存储敏感信息
1. SharedPreferences漏洞, 无法避免,所以不要在里面存储敏感信息2. 数据存储检测,content://com.starcor.launcherInfo/deviceInfo&q ...
- maven:用appassembler-maven-plugin打包含有自定义目录的JAVA程序
问题说明: 用maven构建了一个项目,目录结构如下: appassemblerd的配置: <plugin> <groupId>org.codehaus.mojo</gr ...
- ERP入门
为什么想起写这个题目哪?其实这个问题很久就想写了,记得2005年时候,公司新招的二位刚毕业的大学生,一个专业是经济管理,一个是会计,东北大区培训后公司让我选择了一位带一带,我选择了一个会计专业的(因为 ...
- 关于iOS的runtime
runtime是一个很有意思的东西,如果你学iOS开发很经常就会用到或被问到runtime.那么runtime是什么呢,如何去了解它. runtime:中文名 运行时,系统在编译时留下的一些 类型,操 ...
- 多人开发Xcode工程冲突,打不开解决办法
在公司多人协作开发,相信好多程序员都遇到非常忧伤的问题,就是工程打不开,这样就无从下手,好多程序怨只能再从代码服务器上下载一份新的代码,今天军哥教你几个小技巧,让你的bigger瞬间提升一个档次 在公 ...
- iOS检查App新版本并更新新版本
检查新版本 更新 第一种方法 //检查新版本 更新 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, ...