原则
面向抽象(有纯虚函数的类)而非面向具体类
注意:
在编程中,尽量将抽象类定义为接口,或者避免重写基类非纯虚函数
原因:
1、针对原则,工厂模式的目的就是避免直接在上层代码中实例化类,从而将实例化所带来的具体问题控制在下层代码的一定范围中。才能够在关系复杂的代码中建立逻辑清晰,可读性强,且方便维护的代码结构。
2、在OO程序设计中,要面向接口编程,而非面向实现编程,而C++语言中,以只有纯虚函数和静态成员的类作为接口。
使用接口的优点:
接口的上层代码不需要关心继承接口的有哪些类以及类的具体情况,只需要确定使用到的类有对接口的方法进行重写,并且可以清晰直观的使用多态了,不用担心整体结构混乱,多态的使用会非常的直观。
更重要的是,利用多态,以及上述的原则,也叫依赖倒置原则,可以将上层代码和下层代码以抽象类作为分界线,对于上层代码,使用多态进行操作,就无需关心具体的下层实现,可以将所有操作通过多态整合,使得代码更加简洁,逻辑更加清晰。对于下层代码,可以专注于具体的实现,把问题分而化之,编程就在这样的思考方式下变得顺理成章。
描述
工厂模式主要作用是封装实例化类的过程。
进一步想一下,如果使用面向过程的思考方法,直接在需要对象的时候实例化类,还没开始写,就可以预见代码整体是有多么的跳跃,当需要修改这类代码时,仅仅梳理逻辑都是非常难受的一件事情。这种情况就是比较高程度的依赖。因此在编程中,所有程序员都强调高内聚,低耦合。低耦合就代码比较低的依赖程度。
对于依赖的进一步解释:
耦合/依赖:在一个类的成员函数中实例化了几个不同的类,那么已经实例化的类必须存在,如果代码需要增加同等级别的类,在上级的相关类的成员函数中需要修改代码等,这就是非常高度的耦合情况。
案例
假设我有一个需求,要制作一个面馆的系统。
此时大家都会想到,面馆的三大组成:
1、点单
2、制作面条
3、配送面条
简单工厂模式
如果你想吃一碗简单的街头小吃式面条,可以使用简单工厂模式。
简单工厂模式认为将制作面条交给工厂就可以了。因此简单模式开辟出工厂类,在工厂类中制作具体的面条。就像在平常生活中我们也经常为了方便吃泡面一样。
工厂模式
工厂模式更加讲究,他认为要将面馆做大,未来还有可能开分店,开连锁,因此哪怕只有一家店,也从不放弃做大做强的希望,并为之努力。
于是,工厂模式开辟出长沙分工厂,武汉分工厂,专门做面条。并且这些工厂继承上层工厂接口,都去实现制作面条功能。
此时,长沙工厂就开始制作自己的面条,但是长沙米粉更加好吃,于是面馆开始将面条换成米粉,反正上层只需要他们的动作名字叫作面条,不在乎具体过程。武汉工厂著名的就是热干面,他有自己独到的配方。。。。。。
当有钱的顾客想要吃到正宗的长沙米粉,就可以创建长沙分工厂,制作出来的肯定是正宗的味道。
#include <iostream>
//此类型可以扩展,因此引用代称
typedef int noodle_type;
typedef int sauce_type;
typedef int Sichuan_Pepper;
//面条接口
class Noodle
{
public:
virtual void prepare()=0;
};
//继承了类型接口的类
/****************************************/
class HotDryNoodle:public Noodle
{
public:
HotDryNoodle()
{
pepper = 1;
noodles = 1;
sauce = 1;
}
void prepare()
{
std::cout << " HotDryNoodle prepare" << std::endl;
}
private:
Sichuan_Pepper pepper;
noodle_type noodles;
sauce_type sauce;
};
class RiceNoodle:public Noodle
{
public:
RiceNoodle()
{
noodles = 1;
sauce = 1;
}
void prepare()
{
std::cout << "RiceNoodle prepare" << std::endl;
}
private:
noodle_type noodles;
sauce_type sauce;
};
/***************************************************/
//工厂接口
class NoodleFactory
{
public:
virtual Noodle *create_noodle()=0;
};
/**********************************************/
//继承了工厂接口的不同工厂
class SiChuanFactory:public NoodleFactory
{
public:
Noodle *create_noodle()
{
return new HotDryNoodle();
}
};
class ChangShaFactory:public NoodleFactory
{
public:
Noodle *create_noodle()
{
return new RiceNoodle();
}
};
/*********************************/
//用户代码
class NoodleRestaurant
{
public:
//点单
void oder_noodle(std::string name)
{
noodle = create_noodle(name);
}
void get_noodle()
{
noodle->prepare();
}
private:
//制作面条,非用户操作,因此对用户隐藏
Noodle *create_noodle(std::string name)
{
if ( name == "ChangshaRiceNoodle")
{
noodlefactory = new ChangShaFactory();//
noodle = noodlefactory->create_noodle();
}
else if ( name == "SiChuanNoodle")
{
noodlefactory = new SiChuanFactory();//
noodle = noodlefactory->create_noodle();
}
return noodle;
}
private:
Noodle *noodle;
NoodleFactory *noodlefactory;
};
//测试
int main()
{
NoodleRestaurant noodleRestaurant;
std::string name;
std::string name_2;
name = "ChangshaRiceNoodle";
name_2 = "SiChuanNoodle";
noodleRestaurant.oder_noodle(name_2);
noodleRestaurant.get_noodle();
return 1;
}
抽象工厂模式
抽象工厂模式认为,自己已经是个成熟的网红面馆,必须要有自己的坚持。说做面就做面,用什么配料,都得规范好。毕竟是个大企业,要有自己的坚持。尽管各个分店对面条的口味有不同的追求,但它不管,他需要大家的面组成部分一样。说是花椒就必须有花椒,当然长沙的地里不会长出四川的花椒。于是抽象工厂类中,又要加入原料工厂接口。不同的面条工厂,有它独特的面条配方原料。比如都是花椒,但重庆小面分工厂认为只有重庆的花椒能制作出正宗重庆风味的小面。当需要吃武汉热干面的时候,就建设武汉热干面原料厂,原料和配方都是对的,设还敢说这不是一碗正宗的面。只要面的质量在可控范围内,网红招牌就不会让人失望。
#include <iostream>
//代表类型可扩展,引用别名
typedef int noodle_type;
typedef int sauce_type;
/*************************************/
//原料接口,方便面向接口准则而非面向实现的准则,后续代码可见优点
class Sauce
{
public:
typedef char sauce_test_flag;
};
class Noodle
{
public:
typedef char Noodle_test_flag;
};
/****************************************/
//原料工厂接口,如有上述,可通过多态降低依赖
class IngredientFactory
{
public:
virtual Noodle *create_noodle() = 0;
virtual Sauce *create_sauce() = 0;
};
/****************************************/
//继承原料接口的具体原料类型
class ChangShaSauce:public Sauce
{
public:
ChangShaSauce()
{
sauce = 1;
std::cout << "prepare changsha sauce" << std::endl;
}
private:
sauce_type sauce;
};
class SiChuanSauce:public Sauce
{
public:
SiChuanSauce()
{
sauce = 1;
std::cout << "prepare sichuan sauce" << std::endl;
}
private:
sauce_type sauce;
};
class ChangShaRiceNoodle:public Noodle
{
public:
ChangShaRiceNoodle()
{
noodle = 1;
std::cout << "prepare changsha noodle" << std::endl;
}
private:
noodle_type noodle;
};
class SiChuanNoodle:public Noodle
{
public:
SiChuanNoodle()
{
noodle = 1;
std::cout << "prepare sichuan noodle" << std::endl;
}
private:
noodle_type noodle;
};
/******************************/
/**************************************/
//针对不同地区的不同原料工厂
class ChangShaIngredientFactory:public IngredientFactory
{
public:
Noodle *create_noodle()
{
return new ChangShaRiceNoodle();
}
Sauce *create_sauce()
{
return new ChangShaSauce();
}
};
class SiChuanIngredientFactory:public IngredientFactory
{
public:
Noodle *create_noodle()
{
return new SiChuanNoodle();
}
Sauce *create_sauce()
{
return new SiChuanSauce();
}
};
/***************************************/
//以对象作为切入点
class NNoodle
{
public:
NNoodle(IngredientFactory *ingredientfactory)
{
prepare_nnoodle(ingredientfactory);
}
private:
void prepare_nnoodle(IngredientFactory *ingredientfactory)
{
mynoodle = ingredientfactory->create_noodle();
mysauce = ingredientfactory->create_sauce();
}
private:
Noodle *mynoodle;
Sauce *mysauce;
};
//用户代码
class NoodleRestaurant
{
public:
//点单
void order_noodle(std::string name)
{
//针对菜单创建相应的原料工厂
if(name == "ChangShaNoodle")
ingredientfactory = new ChangShaIngredientFactory();
else if(name == "SiChuanNoodle")
ingredientfactory = new SiChuanIngredientFactory();
//制作由原料工厂原料组成的面条,用户不用在意面条配方,只需要给出名字,一切交给原料工厂
nnoodle = new NNoodle(ingredientfactory);
}
//派送
NNoodle *get_noodle()
{
return nnoodle;
}
private:
NNoodle *nnoodle;
IngredientFactory *ingredientfactory;
};
//测试
int main()
{
NoodleRestaurant noodlerestaurant;
std::string name = "ChangShaNoodle";
std::string name_2 = "SiChuanNoodle";
noodlerestaurant.order_noodle(name);
return 1;
}
书籍
head first设计模式