概要
面向对象除了“谁的事情谁负责”原则外,还有一个就是“该绕路就不能走捷径”。是指存在拥有或者单向访问关系的类对象之间存在的一种访问规则。拥有关系,是指必须通过拥有者才能访问被拥有的对象,单项访问是指甲对象能访问已对象,已对象不能访问甲对象。
例如下面三个类:订单拥有订单项,订单项能访问产品,产品不能访问订单项。
![](https://img-blog.csdnimg.cn/direct/ba25fca23d5b4f308066a16ffea68376.jpeg)
代码如下:
#include <iostream>
#include <string>
using namespace std;
class Order
{
private:
string datetime;
int price;
OrderItem* pOrderitem;//订单拥有订单项 (是拥有的关系)
public:
void Order();
pOrderitem* addItem();
float calculate_price()//计算价格
};
void Order::Order()
{ //...必要的初始化,一个订单可能有多个订单项,
//创建空的订单项集,因为是拥有的关系,所以订单类要“操心”订单项的所有事,
//当然,具体做还得订单项自己去做
OrderItem* pOrderitem = new OrderItem;
}
//实际项目中,根据用户购买的产品随时创建订单项,如果在其他地方创建,
//可以通过参数传递,总之都要交给 pOrderitem管理,才能体现拥有关系
pOrderitem* Order::addItem(/*OrderItem&*/)
{
pOrderitem++;
pOrderitem = &OrderItem; //追加到订单项集末尾,可以有不同写法
}
float Order::calculate_price()
{
for(..;pOrderitem;..)//每个订单项都要计算
price = price + pOrderitem->calculate_cost();//实际上要交给订单项去算价格
}
class OrderItem
{
private:
int num;//购买数量
float cost;//订单项价格(不是单价)
public:
float calculate_cost()
{
string name="电饭锅"//此时,订单项已经能决定要哪个产品了,
//实际项目中,产品名称或者其ID取自界面;
//产品和订单项不是拥有的关系,所以可在订单项类里随时、
//临时地创建对象(不是拥有关系就不需要将其作为订单项的一个成员)
Product* p = new Product(name);
return p->getUnitprice() * num;//数量是订单项的,单价是产品的
}
};
class Product
{
private:
string productName;
float unitPrice;
public:
void Product(string name)
{
productName = name;
//... 再根据产品名称获得unitPrice,来源包括数据库等
}
float getUnitprice();
};
int main() {
Order order1;
//...
order1.calculate_price();
return 0;
}
总结:
- 订单“不知道”产品的存在,因此,从来不会直接访问产品,都要通过订单项来访问;
- 要计算订单总价,需要通过订单项去算,订单项计算时缺产品单价,获取单价就必须交给产品去做;这就是谁的事情谁负责,见上一个文章。
- 类之间拥有的关系,即模型上的菱形线,代码中体现为数据成员,和数据库实体的外键不是一回事;
- 订单项和产品之间的单项箭头,是指订单项能访问产品,即订单项类里可以创建产品的临时对象,但产品类中不允许创建订单项对象,否则就是双向箭头,直接画成一条线就可以双向访问了;
- 模型中类之间访问关系同样不是数据库实体的主外键的关系,所以一个类中没有另外一个类的ID或者名字;
- 这里解释一下怎么确定的拥有关系和单向访问关系,因为订单项只能被订单拥有,它自己单独存在没什么意义,产品不一样,考虑可重用性因素,产品单价可单独维护,一般对接产品库存系统,有没有订单订单项,产品以及库存都存在。