一个有趣的例子带你看面向对象编程与面向过程编程的主要区别

昨天,有小伙伴问我面向对象编程跟面向过程编程的主要区别是什么。面向对象编程又有什么优势。
针对这两个问题,我们不妨举个例子。

情景描述

家住四川的小浩手抓饼店,清单如下:
在这里插入图片描述

小浩做的手抓饼香脆可口,再加上小浩的独家配方,吸引了许多当地人来品尝小浩做的手抓饼。
由于经营有方,小浩赚得盆满钵满,但小浩很有雄心,想在其他地方开连锁店。为了保证各连锁店做的手抓饼基本一致,小浩决定所有连锁店手抓饼制作的独家配方统一由总店放送。
其中有一家打算开在山东,经过实地考察,小浩发现山东人并不是很能吃辣,但他们喜欢放五香等。小浩因此微调了山东连锁店的加料菜单。
在这里插入图片描述

问题

现在小浩想要你设计一套系统帮助他管理他的连锁店。
主要功能:

  1. 计算每份订单价格
  2. 提供每份订单的制作流程

面向对象VS面向过程

面向过程

//四川连锁店
//四川饼价格计算
//手抓饼
double SichuanbingPrice() {
	return 5.0;
}
//麻辣火腿
double MalahuotuiPrice() {
	return 1.2;
}
//麻辣鸡排
double MalajipaiPrice() {
	return 2.30;
}
//香辣猪排
double XianglazhupaiPrice() {
	return 1.0;
}
double SichuanSumPrice(vector<int> &foods) {
	double sum = 0.0;
	for (size_t i = 0; i < foods.size(); i++) {
		if (foods[i] == 0) {
			sum += SichuanbingPrice();
		}
		if (foods[i] == 1) {
			sum += MalahuotuiPrice();
		}
		if (foods[i] == 2) {
			sum += MalajipaiPrice();
		}
		if (foods[i] == 3) {
			sum += XianglazhupaiPrice();
		}
	}
	return sum;
}
//四川手抓饼制作
void SichuanMake(vector<int> &foods) {
	cout << "此处利用小浩的手抓饼制作工艺来制作(连锁店不得更改)" << endl;
	string temp = "";
	for (size_t i = 0; i < foods.size(); i++) {
		if (foods[i] == 0) {
			temp += " 加入饼 ";
		}
		if (foods[i] == 1) {
			temp += " 加入麻辣火腿 ";
		}
		if (foods[i] == 2) {
			temp += " 加入麻辣鸡排 ";
		}
		if (foods[i] == 3) {
			temp += " 加入香辣猪排 ";
		}
	}
	cout << temp << endl;
	cout << "加入小浩独家配方(连锁店不得更改)" << endl;

}

//山东连锁店
//山东手抓饼价格计算
//手抓饼
double ShandongbingPrice() {
	return 5.0;
}
//五香火腿
double WuxianghuotuiPrice() {
	return 1.5;
}
//五香鸡排
double WuxiangjipaiPrice() {
	return 2.0;
}
//五香猪排
double WuxiangzhupaiPrice() {
	return 1.0;
}
double ShandongSumPrice(vector<int> &foods) {
	double sum = 0.0;
	for (size_t i = 0; i < foods.size(); i++) {
		if (foods[i] == 0) {
			sum += ShandongbingPrice();
		}
		if (foods[i] == 1) {
			sum += WuxianghuotuiPrice();
		}
		if (foods[i] == 2) {
			sum += WuxiangjipaiPrice();
		}
		if (foods[i] == 3) {
			sum += WuxiangzhupaiPrice();
		}
	}
	return sum;
}
//山东手抓饼制作
void ShandongMake(vector<int> &foods) {
	cout << "此处利用小浩的手抓饼制作工艺来制作(连锁店不得更改)" << endl;
	string temp = "";
	for (size_t i = 0; i < foods.size(); i++) {
		if (foods[i] == 0) {
			temp += " 加入饼 ";
		}
		if (foods[i] == 1) {
			temp += " 加入五香火腿 ";
		}
		if (foods[i] == 2) {
			temp += " 加入五香鸡排 ";
		}
		if (foods[i] == 3) {
			temp += " 加入五香猪排 ";
		}
	}
	cout << temp << endl;
	cout << "加入小浩独家配方(连锁店不得更改)" << endl;

}

面向对象

我们首先根据需求,仿照简单工厂模式设计类图
我们设计了两个基类:一个是手抓饼的基类:foodbase(产品)一个是连锁店的基类:storebase(工厂)
在这里插入图片描述
在这里插入图片描述
根据上述类图设计类

class FoodBase {
public :
	FoodBase() = default;
	virtual double getPrice() =0;
	virtual string getMethod() = 0;
};
class ShandongFoods :public FoodBase {
public:
	ShandongFoods() = default;
};

class Wuxianghuotui :public ShandongFoods {
public:
	Wuxianghuotui() = default;
	double getPrice() {
		return 1.5;
	}
	string getMethod() {
		return " 加入五香火腿 ";
	}
};
class Wuxiangjipai :public ShandongFoods {
public:
	Wuxiangjipai() = default;
	double getPrice() {
		return 2.0;
	}
	string getMethod() {
		return " 加入五香鸡排 ";
	}
};

class Wuxiangzhupai :public ShandongFoods {
public:
	Wuxiangzhupai() = default;
	double getPrice() {
		return 1.0;
	}
	string getMethod() {
		return " 加入五香猪排 ";
	}
};

class Shandongbing :public ShandongFoods {
public:
	Shandongbing() = default;
	double getPrice() {
		return 5.0;
	}
	string getMethod() {
		return " 加一份饼 ";
	}
};

//Sichuan
class SichuanFoods :public FoodBase {
public:
	SichuanFoods() = default;
};

class Malahuotui :public SichuanFoods {
public:
	Malahuotui() = default;
	double getPrice() {
		return 1.2;
	}
	string getMethod() {
		return " 加入麻辣火腿 ";
	}
};
class Malajipai :public SichuanFoods {
public:
	Malajipai() = default;
	double getPrice() {
		return 2.3;
	}
	string getMethod() {
		return " 加入麻辣鸡排 ";
	}
};

class Sichuanbing :public SichuanFoods {
public:
	Sichuanbing() = default;
	double getPrice() {
		return 5.0;
	}
	string getMethod() {
		return " 加一份饼 ";
	}
};

class Xianglazhupai :public SichuanFoods {
public:
	Xianglazhupai() = default;
	double getPrice() {
		return 1.0;
	}
	string getMethod() {
		return " 加入香辣猪排 ";
	}
};


class StoreBase {
public:
	StoreBase() = default;
	virtual string getMethods() = 0;
	virtual double getPrice() = 0;
protected:
	string first_step, last_step;
	vector<int> foods_list;
	
	
private:
	void setSecret() {
		first_step = "此处利用小浩的手抓饼制作工艺来制作(连锁店不得更改)";
		last_step = "加入小浩独家配方(连锁店不得更改)";
	}
	
};
class ShandongStore :public StoreBase {
public:
	ShandongStore(vector<int>foods) {
		foods_list = foods;
	}
	string getMethods() {
		string method = "";
		method += first_step + "\n";
		ShandongFoods *shandong_foods = nullptr;
		for (size_t i = 0; i < foods_list.size(); i++) {
			if (foods_list[i] == 0) {
				shandong_foods = new Shandongbing;
				method += shandong_foods->getMethod();
			}
			if (foods_list[i] == 1) {
				shandong_foods = new Wuxianghuotui;
				method += shandong_foods->getMethod();
			}
			if (foods_list[i] == 2) {
				shandong_foods = new Wuxiangjipai;
				method += shandong_foods->getMethod();
			}
			if (foods_list[i] == 3) {
				shandong_foods = new Wuxiangzhupai;
				method += shandong_foods->getMethod();
			}
		}
		delete shandong_foods;
		method += "\n"+last_step+"\n";
		return method;
	}
	double getPrice() {
		double price = 0.0;
		ShandongFoods *shandong_foods = nullptr;
		for (size_t i = 0; i < foods_list.size(); i++) {
			if (foods_list[i] == 0) {
				shandong_foods = new Shandongbing;
				price += shandong_foods->getPrice();
			}
			if (foods_list[i] == 1) {
				shandong_foods = new Wuxianghuotui;
				price += shandong_foods->getPrice();
			}
			if (foods_list[i] == 2) {
				shandong_foods = new Wuxiangjipai;
				price += shandong_foods->getPrice();
			}
			if (foods_list[i] == 3) {
				shandong_foods = new Wuxiangzhupai;
				price += shandong_foods->getPrice();
			}
		}
		delete shandong_foods;
		return price;
	}

};


class SichuanStore :public StoreBase {
public:
	SichuanStore(vector<int>foods) {
		foods_list = foods;
	}
	string getMethods() {
		string method = "";
		method += first_step + "\n";
		SichuanFoods *sichuan_foods = nullptr;
		for (size_t i = 0; i < foods_list.size(); i++) {
			if (foods_list[i] == 0) {
				sichuan_foods = new Sichuanbing;
				method += sichuan_foods->getMethod();
			}
			if (foods_list[i] == 1) {
				sichuan_foods = new Malahuotui;
				method += sichuan_foods->getMethod();
			}
			if (foods_list[i] == 2) {
				sichuan_foods = new Malajipai;
				method += sichuan_foods->getMethod();
			}
			if (foods_list[i] == 3) {
				sichuan_foods = new Xianglazhupai;
				method += sichuan_foods->getMethod();
			}
		}
		delete sichuan_foods;
		method += "\n" + last_step + "\n";
		return method;
	}
	double getPrice() {
		double price = 0.0;
		SichuanFoods *sichuan_foods = nullptr;
		for (size_t i = 0; i < foods_list.size(); i++) {
			if (foods_list[i] == 0) {
				sichuan_foods = new Sichuanbing;
				price += sichuan_foods->getPrice();
			}
			if (foods_list[i] == 1) {
				sichuan_foods = new Malahuotui;
				price += sichuan_foods->getPrice();
			}
			if (foods_list[i] == 2) {
				sichuan_foods = new Malajipai;
				price += sichuan_foods->getPrice();
			}
			if (foods_list[i] == 3) {
				sichuan_foods = new Xianglazhupai;
				price += sichuan_foods->getPrice();
			}
		}
		delete sichuan_foods;
		return price;
	}

};

在这里插入图片描述

(以上例子皆为虚构)

面向对象优势

模块化

面向过程编程里大量函数无逻辑地存放在一起,当函数变多时不易于管理。
在这里插入图片描述

面向对象编程中的函数被封装,具有一定逻辑的函数放在一起,并且当几个利用相同参数的函数封装在一个类中时,不需要重复传参。(如上图所示getMethods、getPrice函数都需要foods变量,当被封装在类中时,可以直接用构造函数接收变量值,之后便无需传参了)

保护机制

在小浩的要求中,第一步的手抓饼制作以及独家秘方的添加是必须按照总店要求做的,连锁店不能自己修改。
在这里插入图片描述
在面向过程编程中,这两个直接写到跟其他佐料制作中,保护机制很差。
在这里插入图片描述对于面向对象方法,必须强制执行且具有机密性的两个方法写在基类的private里,这样子类就无法修改这些方法了。

易于扩展

对于面向对象编程,如果想要新增菜单或者其他地区的连锁店时,只需扩展相应类即可,控制类中改动不大。
但对于面向过程编程,控制类中仍需要更改新增的信息。

易于维护

在这里插入图片描述
上图中,左图是面向过程编程,右图是面向对象编程。
如果想要更改五香火腿的制作方法,对于面向对象方法,我们直接去五香火腿对应的类里修改他的制作函数即可。但对于面向过程方法,我们却需要去整个流程的制作函数中修改。

复用性强

可观察多个实现的共性以及个性,将共性封装成方法,个性则以传参的方式来适配不同业务的需求。从而提高了功能的内聚性,降低与业务代码之间的耦合性,履行封装的单一责任原则。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值