一道经典面试题透彻理解面向对象编程思想和简单工厂模式

2023-10-27

一道经典的面试题如下:

用一种面向对象编程语言实现一个计算器来满足整数的加减乘除运算。

大部分人的代码如下:

1.0版本

#include<iostream>
using namespace std;
#include<string>
//1.0版本
int main()
{
	int num1 = 0;
	int num2 = 0;
	string ope = " ";
	int re = 0;
	cout << "请输入左操作数:" << endl;
	cin >> num1;
	cout << "请输入右操作数:" << endl;
	cin >> num2;
	cout << "请输入操作符" << endl;
	cin >> ope;

	if (ope == "+")
	{
		re = num1 + num2;
	}
	if (ope == "-")
	{
		re = num1 - num2;
	}
	if (ope == "*")
	{
		re = num1 * num2;
	}
	if (ope == "/")
	{
		re = num1 / num2;
	}
	
	cout << re << endl;

	return 0;
}

这段代码,主要出现两个问题。首先,该段代码没有使用if-else-if语句,而是直接使用4段if语句,这意味着每个条件都要进行判断,计算机只要执行该程序就一定会做3次无用功,其次,在执行加减乘除的时候,如果客户输入的操作数是非数字形式,输入的操作符是非规定符号,以及在执行除法的时候,如果客户右操作数输入的是0怎么办,也就是说该段代码没有考虑到异常情况。

那么优化后的代码如下:

2.0版本

#include<iostream>
using namespace std;
#include<string>

class opeException
{
public:
	void getMessage()
	{
		cout << "您的输入有误!" << endl;
	}
};

//判断一个字符串是不是数字
bool isStringNum(string& s)
{
	bool flag = true;
	for (auto e : s)
		if (!isdigit(e))
		{
			flag = false;
			break;
		}	
	return flag;
}

int main()
{
	string num1 = "0";
	string num2 = "0";
	string ope = " ";

	try
	{
		cout << "请输入左操作数:" << endl;
		cin >> num1;
		if (!isStringNum(num1))
			throw opeException();

		cout << "请输入右操作数:" << endl;
		cin >> num2;
		if (!isStringNum(num2))
			throw opeException();

		cout << "请输入操作符" << endl;
		cin >> ope;
		if (ope != "+" && ope != "-" && ope != "*" && ope != "/")
			throw opeException();
		

		if (ope == "+")
		{
			cout<< stoi(num1) + stoi(num2)<<endl;
		}
		else if (ope == "-")
		{
			cout << stoi(num1) - stoi(num2) << endl;
		}
		else if (ope == "*")
		{
			cout << stoi(num1) * stoi(num2) << endl;
		}
		else if (ope == "/")
		{
			if (stoi(num2) != 0)
			{
				cout << stoi(num1) / stoi(num2) << endl;
			}
			else
				cout << "除数不能为0" << endl;
			
		}
	}
	catch (opeException ex)
	{
		ex.getMessage();
	}

	return 0;
}

解决了if语句以及异常情况之后,这段代码对于面试官来说就是合格的了吗?

答案显然是否定的,因为面试官让我们用面向对象语言来实现一个计算器,为何不使用C语言等面向过程语言来实现?因为他实际是想让我们在编程中体现面向对象思想,即封装、继承和多态思想。虽然我们用的是面向对象语言,但是上面的编程思想依旧是面向过程的,利用面向过程思想写出来的代码,不易维护,不易扩展,不易复用,会经常出现因为客户改需求,导致对程序进行大刀阔斧动手术的情况。

我们在编程中应该注重面向对象思想,利用封装、继承和多态,将程序之间的耦合度降低。

现在我们就利用面向对象思想来修改这个计算器程序。

首先,我们应当将业务逻辑和界面逻辑分开,即让计算和显示分开,这样计算是计算,显示是显示,计算和显示之间的耦合度就降低了。

3.0版本

#include<iostream>
using namespace std;
#include<string>

//业务逻辑
//异常类用于处理异常情况
class opeException
{
public:
	void getMessage()
	{
		cout << "您的输入有误!" << endl;
	}
};

//运算类用于处理运算
class Operation
{
public:
	Operation(string& _num1, string& _num2, string& _ope) :num1(_num1), num2(_num2), ope(_ope){}
		//获取运算结果
	int getResult()
	{
		if (!(isStringNum(num1) && isStringNum(num2) && (ope == "+" || ope == "-" || ope == "*" || ope == "/")))
			throw opeException();
		if (ope == "+")
		{
			re = stoi(num1) + stoi(num2);
		}
		else if (ope == "-")
		{
			re = stoi(num1) - stoi(num2);
		}
		else if (ope == "*")
		{
			re = stoi(num1) * stoi(num2);
		}
		else if (ope == "/")
		{
			if (stoi(num2) != 0)
			{
				re = stoi(num1) / stoi(num2);
			}
			else
				throw opeException();
		}

		return re;
	}
private:
	int re;
	string num1;
	string num2;
	string ope;

	//判断一个字符串是不是数字
	bool isStringNum(string& s)
	{
		bool flag = true;
		for (auto e : s)
			if (!(isdigit(e)))
			{
				flag = false;
				break;
			}
		return flag;
	}
};

//界面逻辑
int main()
{
	try
	{
		string _num1 = " ";
		string _num2 = " ";
		string _ope = " ";

		cout << "请输入左操作数:" << endl;
		cin >> _num1;


		cout << "请输入右操作数:" << endl;
		cin >> _num2;

		cout << "请输入操作符" << endl;
		cin >> _ope;

		Operation operation(_num1, _num2, _ope);
		cout << operation.getResult() << endl;
	}
	catch (opeException &ex)
	{
		ex.getMessage();
	}

	return 0;
}

实际上,将运算和界面分离,将运算所需要的操作数,运算符和运算方法封装成一个类,已经体现了面向对象中的封装思想,但这远远还不够。

如果我们要进行除法运算,还得在条件语句中判断是否是加法运算,然后判断是否是减法运算,再判断是否是乘法运算,效率依然比较低,而且如果我们要增加一个运算,又得增加一个if语句进行判断,那我们要增加10个运算,岂不是要增加10个if语句进行判断,而且还有可能不小心把之前的if语句修改,这就是面向过程思想的缺陷,极不易维护,不易拓展,且不易复用!而且,getResult函数中连续的if语句又是一个典型的面向过程的思想,这也提醒我们是不是可以把if语句中连续的运算判断封装成一个类呢?

因此我们考虑不仅仅把运算封装成一个类,把具体的各个运算也封装成一个类,需要哪个运算,就创建哪个运算的对象。

4.0版本

//4.0版本

#include<iostream>
using namespace std;
#include<string>

//业务逻辑
 
//异常类用于处理异常情况
class opeException
{
public:
	void getMessage()
	{
		cout << "您的输入有误!" << endl;
	}
};

//运算类
class Operation
{	
	//判断一个字符串是不是数字
	bool isStringNum(string& s)
	{
		bool flag = true;
		for (auto e : s)
			if (!(isdigit(e)))
			{
				flag = false;
				break;
			}
		return flag;
	}

protected:
//判断输入的操作数和操作符是否有误
	bool isError(string& _strNum1, string& _strNum2, string& _ope)
	{
		if (!(Operation::isStringNum(_strNum1) && Operation::isStringNum(_strNum2) && (_ope == "+" || _ope == "-" || _ope == "*" || _ope == "/")))
		{
			return false;
		}
	}
public:
	virtual int getResult() = 0;
};

//加法运算类
class addOperation:public Operation
{
private:
	string strNum1;
	string strNum2;
	string ope;
	int re;
public:
	addOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1),strNum2(_strNum2),ope(_ope),re(0) {}
	virtual int getResult() override
	{
		if (!isError(strNum1, strNum2, ope))
			throw opeException();
		else
			re = stoi(strNum1) + stoi(strNum2);

		return re;
	}
};

//减法运算类
class subOperation :public Operation
{
private:
	string strNum1;
	string strNum2;
	string ope;
	int re;
public:
	subOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}
	virtual int getResult() override
	{
		if (!isError(strNum1, strNum2, ope))
			throw opeException();
		else
			re = stoi(strNum1) - stoi(strNum2);

		return re;
	}
};

//乘法运算类
class mulOperation :public Operation
{
private:
	string strNum1;
	string strNum2;
	string ope;
	int re;
public:
	mulOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}
	virtual int getResult() override
	{
		if (!isError(strNum1, strNum2, ope))
			throw opeException();
		else
			re = stoi(strNum1) * stoi(strNum2);

		return re;
	}
};

//除法运算类
class divOperation :public Operation
{
private:
	string strNum1;
	string strNum2;
	string ope;
	int re;
public:
	divOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}
	virtual int getResult() override
	{
		if (!isError(strNum1, strNum2, ope))
			throw opeException();
		else if (stoi(strNum2) != 0)
			re = stoi(strNum1) / stoi(strNum2);
		else
			throw opeException();

		return re;
	}
};

//界面逻辑
int main()
{
	try
	{
		string _strNum1 = " ";
		string _strNum2 = " ";
		string _ope = " ";

		cout << "请输入左操作数:" << endl;
		cin >> _strNum1;

		cout << "请输入右操作数:" << endl;
		cin >> _strNum2;

		cout << "请输入操作符:" << endl;
		cin >> _ope;

		if (_ope == "+")
		{
			addOperation addoperation(_strNum1, _strNum2, _ope);
			cout << addoperation.getResult() << endl;
		}
		else if (_ope == "-")
		{
			subOperation suboperation(_strNum1, _strNum2, _ope);
			cout << suboperation.getResult() << endl;
		}
		else if (_ope == "*")
		{
			mulOperation muloperation(_strNum1, _strNum2, _ope);
			cout << muloperation.getResult() << endl;
		}
		else if (_ope == "/")
		{
			divOperation muloperation(_strNum1, _strNum2, _ope);
			cout << muloperation.getResult() << endl;
		}
		else
			cout << "您的输入有误!" << endl;
			
	}
	catch (opeException ex)
	{
		cout << "您的输入有误" << endl;
	}

	return 0;
}

本版本计算器代码虽然充分利用了面向对象的三大特性:封装、继承和多态,但是还是有点问题,因为最后判断到底实例化哪种运算符,是通过多个if语句判断的,这是一个典型的面向过程思想,而且该思想将界面逻辑和业务逻辑又混合了,所以我们在新版本的代码中要修改这种面向过程思想,这里我们可以利用一个设计模式,即简单工厂模式,其核心思想就是考虑用单独的类根据实际情况来创造不同类的实例。

5.0版本

#include<iostream>
using namespace std;
#include<string>

//业务逻辑

//异常类用于处理异常情况
class opeException
{
public:
	void getMessage()
	{
		cout << "您的输入有误!" << endl;
	}
};

//运算类
class Operation
{
	//判断一个字符串是不是数字
	bool isStringNum(string& s)
	{
		bool flag = true;
		for (auto e : s)
			if (!(isdigit(e)))
			{
				flag = false;
				break;
			}
		return flag;
	}

protected:
	bool isError(string& _strNum1, string& _strNum2, string& _ope)
	{
		if (!(Operation::isStringNum(_strNum1) && Operation::isStringNum(_strNum2) && (_ope == "+" || _ope == "-" || _ope == "*" || _ope == "/")))
		{
			return false;
		}
	}
public:
	virtual int getResult() = 0;
};

//加法运算类
class addOperation :public Operation
{
private:
	string strNum1;
	string strNum2;
	string ope;
	int re;
public:
	addOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}
	virtual int getResult() override
	{
		if (!isError(strNum1, strNum2, ope))
			throw opeException();
		else
			re = stoi(strNum1) + stoi(strNum2);

		return re;
	}
};

//减法运算类
class subOperation :public Operation
{
private:
	string strNum1;
	string strNum2;
	string ope;
	int re;
public:
	subOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}
	virtual int getResult() override
	{
		if (!isError(strNum1, strNum2, ope))
			throw opeException();
		else
			re = stoi(strNum1) - stoi(strNum2);

		return re;
	}
};

//乘法运算类
class mulOperation :public Operation
{
private:
	string strNum1;
	string strNum2;
	string ope;
	int re;
public:
	mulOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}
	virtual int getResult() override
	{
		if (!isError(strNum1, strNum2, ope))
			throw opeException();
		else
			re = stoi(strNum1) * stoi(strNum2);

		return re;
	}
};

//除法运算类
class divOperation :public Operation
{
private:
	string strNum1;
	string strNum2;
	string ope;
	int re;
public:
	divOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {}
	virtual int getResult() override
	{
		if (!isError(strNum1, strNum2, ope))
			throw opeException();
		else if (stoi(strNum2) != 0)
			re = stoi(strNum1) / stoi(strNum2);
		else
			throw opeException();

		return re;
	}
};

//运算工厂类
class OpeFactory
{
public:
	Operation& choose(string &_strNum1,string &_strNum2,string &_ope)
	{

		if (_ope == "+")
		{
			operation = new addOperation(_strNum1, _strNum2, _ope);
		}
		else if (_ope == "-")
			operation = new subOperation(_strNum1, _strNum2, _ope);
		else if (_ope == "*")
			operation = new mulOperation(_strNum1, _strNum2, _ope);
		else if (_ope == "/")
		{
			operation = new divOperation(_strNum1, _strNum2, _ope);
		}
		else
			operation = nullptr;
			
		return *operation;
	}
	
private:
	Operation* operation;
};

//界面逻辑
int main()
{
	try
	{
		string _strNum1 = " ";
		string _strNum2 = " ";
		string _ope = " ";

		cout << "请输入左操作数:" << endl;
		cin >> _strNum1;

		cout << "请输入右操作数:" << endl;
		cin >> _strNum2;

		cout << "请输入操作符:" << endl;
		cin >> _ope;

		OpeFactory factory;

		Operation* re = &factory.choose(_strNum1, _strNum2, _ope);
		if (re != nullptr)
			cout << (*re).getResult() << endl;
		else
			cout << "您的输入有误!" << endl;

	}
	catch (opeException ex)
	{
		ex.getMessage();
	}

	return 0;
}

5.0版本的计算器封装了7个类,其中四个加减乘除运算类继承自运算类,四则运算类根据自己的需要实现其基类的纯虚函数(多态),将界面逻辑与业务逻辑完美分隔开,充分利用了面向对象编程思想。

利用了面向对象编程思想的代码就是更加容易维护、拓展、复用。以后我们需要更改加法运算只需要更改AddOperation类即可,如果要修改界面,就直接去改界面,也不会影响到运算,以后我们想添加其他运算,比如开平方运算,立方运算等,只需要添加相应的子类,然后在工厂类中添加相应的分支即可,对其他代码没有任何影响。而如果是利用了面向过程思想的代码,我们在修改,拓展的时候,就要去程序中找到相应的位置,然后叠加代码,这很有可能会影响到前面的代码!

上述代码中,我们利用了简单工厂模式,我们已经知道了简单工厂模式的核心思想,但同时也要了解它的优缺点和使用场景。

优点:

工厂类是整个模式的关键,包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体类的对象,通过使用工厂类,外界可以从直接创建具体对象的尴尬局面摆脱出来,仅仅需要负责使用对象就可以了,而不必管这些对象究竟如何创建及如何组织的,明确了各自的职责和权利,将业务逻辑和界面逻辑进行了分离,有利于整个软件体系结构的优化。

缺点:

由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则就需要改变工厂类了。

当系统中的类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求,这种对条件的判断和对具体类的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利;这些缺点在工厂方法模式中得到了一定的克服。

使用场景:

由于简单工厂很容易违反高内聚责任分配原则,因此一般只在工厂类负责创建的对象比较少的这种简单情况下使用。

本篇博客参考资料:《大话设计模式》

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

一道经典面试题透彻理解面向对象编程思想和简单工厂模式 的相关文章

  • boost::asio + std::future - 关闭套接字后访问冲突

    我正在编写一个简单的 TCP 客户端来发送和接收单行文本 异步操作由 std future 处理 以便于超时阻塞查询 不幸的是 我的测试应用程序在破坏服务器对象时因访问冲突而崩溃 这是我的代码 TCP客户端 hpp ifndef TCPCL
  • 为什么相同的代码在同一台计算机上的执行时间可能不同?

    我是 C 编程新手 我编写了代码并希望获得它的运行时 这就是我所做的 每次运行代码时 我都会得到不同的运行时值 这样对吗 或者我的代码有问题吗 int main int argc char argv time t start end sta
  • c和java语言中的换行符

    现在行分隔符取决于系统 但在 C 程序中我使用 n 作为行分隔符 无论我在 Windows 还是 Linux 中运行它都可以正常工作 为什么 在java中 我们必须使用 n 因为它与系统相关 那么为什么我们在c中使用 n 作为新行 而不管我
  • VB.NET 相当于 C# 属性简写吗?

    是否有与 C 等效的 VB NET public string FirstName get set 我知道你能做到 Public Property name As String Get Return name ToString End Ge
  • 如何在 C# 中从 UNIX 纪元时间转换并考虑夏令时?

    我有一个从 unix 纪元时间转换为 NET DateTime 值的函数 public static DateTime FromUnixEpochTime double unixTime DateTime d new DateTime 19
  • 如何为 C 分配的 numpy 数组注册析构函数?

    我想在 C C 中为 numpy 数组分配数字 并将它们作为 numpy 数组传递给 python 我可以做的PyArray SimpleNewFromData http docs scipy org doc numpy reference
  • 如何将 #ifdef DEBUG 添加到 Xcode?

    我的项目中有一些代码永远不应该在发布版本中使用 但在测试时很有用 我想做这样的事情 ifdef DEBUG Run my debugging only code endif 在 Xcode 4 中哪里添加 DEBUG 设置 我尝试将其放入
  • 读取文件特定行号的有效方法。 (奖励:Python 手册印刷错误)

    我有一个 100 GB 的文本文件 它是来自数据库的 BCP 转储 当我尝试导入它时BULK INSERT 我在第 219506324 行上收到一个神秘错误 在解决此问题之前 我想看看这一行 但可惜的是我最喜欢的方法 import line
  • 如何访问另一个窗体上的ListView控件

    当单击与 ListView 所在表单不同的表单中的按钮时 我试图填充 ListView 我在 Form1 中创建了一个方法以在 Form2 中使用 并将参数传递给 Form1 中的方法 然后填充 ListView 当我调试时 我得到了传递的
  • 单击 form2 上的按钮触发 form 1 中的方法

    我对 Windows 窗体很陌生 我想知道是否可以通过单击表单 2 中的按钮来触发表单 1 中的方法 我的表格 1 有一个组合框 我的 Form 2 有一个 保存 按钮 我想要实现的是 当用户单击表单 2 中的 保存 时 我需要检查表单 1
  • Rx 中是否有与 Task.ContinueWith 运算符等效的操作?

    Rx 中是否有与 Task ContinueWith 运算符等效的操作 我正在将 Rx 与 Silverlight 一起使用 我正在使用 FromAsyncPattern 方法进行两个 Web 服务调用 并且我想这样做同步地 var o1
  • 在一个字节中存储 4 个不同的值

    我有一个任务要做 但我不知道从哪里开始 我不期待也绝对不想要代码中的答案 我想要一些关于该怎么做的指导 因为我感到有点失落 将变量打包和解包到一个字节中 您需要在一个字节中存储 4 个不同的值 这些值为 NAME RANGE BITS en
  • HttpWebRequest 在第二次调用时超时

    为什么以下代码在第二次 及后续 运行时超时 代码挂在 using Stream objStream request GetResponse GetResponseStream 然后引发 WebException 表示请求已超时 我已经尝试过
  • 如何从main方法调用业务对象类?

    我已将代码分为业务对象 访问层 如下所示 void Main Business object public class ExpenseBO public void MakeExpense ExpensePayload payload var
  • 用于 C# 的 TripleDES IV?

    所以当我说这样的话 TripleDES tripledes TripleDES Create Rfc2898DeriveBytes pdb new Rfc2898DeriveBytes password plain tripledes Ke
  • 为什么在setsid()之前fork()

    Why fork before setsid 守护进程 基本上 如果我想将一个进程与其控制终端分离并使其成为进程组领导者 我使用setsid 之前没有分叉就这样做是行不通的 Why 首先 setsid 将使您的进程成为进程组的领导者 但它也
  • 如何在按钮单击时模拟按键 - Unity

    我对 Unity 中的脚本编写非常陌生 我正在尝试创建一个按钮 一旦单击它就需要模拟按下 F 键 要拾取一个项目 这是我当前的代码 在编写此代码之前我浏览了所有统一论坛 但找不到任何有效的东西 Code using System Colle
  • 如何将 Roslyn 语义模型返回的类型符号名称与 Mono.Cecil 返回的类型符号名称相匹配?

    我有以下代码 var paramDeclType m semanticModel GetTypeInfo paramDecl Type Type Where paramDeclType ToString returns System Col
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当
  • 在客户端系统中安装后桌面应用程序无法打开

    我目前正在使用 Visual Studio 2017 和 4 6 1 net 框架 我为桌面应用程序创建了安装文件 安装程序在我的系统中完美安装并运行 问题是安装程序在其他计算机上成功安装 但应用程序无法打开 edit 在客户端系统中下载了

随机推荐

  • 该文件没有与之关联的应用程序来执行该操作。请安装应用,请在"默认应用设置"页面中创建关联

    最近在win10新安装的一个应用程序 在程序中打开指定文件时报了 该文件没有与之关联的应用程序来执行该操作 请安装应用 请在默认应用设置 页面中创建关联 原因是该文件没有默认的打开程序 如果是txt或xml这些文件 可以右击这个文件 设置其
  • vscode缩进和Eslint缩进问题解决

    vscode缩进和Eslint缩进问题解决 vscode更改换行时的缩进 如果更改失效 取消该属性勾选 Eslint 缩进校验修改
  • 解决问题记录2:项目内使用lombok的@Log4j2失效

    问题描述 在使用Log4j2注解后 程序中使用log 启动加载时报错 找不到相对的依赖 检查lombok的依赖是正确的添加的 问题解决 尝试了网上的众多方法都没有解决 后想到是否是有其他的jar内做了lombok的依赖 导致依赖到了其他ja
  • JSP使用最简单的echarts图入门

    jsp使用最简单的echarts图表 jsp项目中应用最简单的一个折线图 柱状图等 一 echarts官网使用 首先打开echarts的api官方文档 官网 https echarts apache org examples zh inde
  • 算法的复杂度

    常用的算法的时间复杂度和空间复杂度 排序法 最差时间分析 平均时间复杂度 稳定度 空间复杂度 冒泡排序 O n2 O n2 稳定 O 1 快速排序 O n2 O n log2n 不稳定 O log2n O n 选择排序 O n2 O n2
  • 我在知乎学写作

    最懂技术的传播者 最懂传播的工程师 最近被知乎成功 忽悠 报名了一个 写作新人培养计划 的课程 写作新人 这老黄瓜未免也太能给自己刷绿漆了吧 心里头想着 还是得push自己 在内容创作的道路上 搞点事情啊 咋回事呢 为什么是知乎 从媒体江湖
  • Ubuntu20.04 ROS noetic安装教程

    注意 本贴是ros官网的方法 使用ros原版官方源 不是国内镜像 适合网络环境比较好的小伙伴 添加源 sudo sh c echo deb http packages ros org ros ubuntu lsb release sc ma
  • NUC980开源项目6-获取官方源码

    上面是我的微信和QQ群 欢迎新朋友的加入 项目码云地址 国内下载速度快 https gitee com jun626 nuc980 open source project 项目github地址 https github com Jun117
  • vulnhub靶机Thoth-Tech

    下载地址 https download vulnhub com thothtech Thoth Tech ova 主机发现 arp scan l 目标 192 168 21 148 端口扫描 nmap min rate 10000 p 19
  • 页面服务器不稳定因为什么,关于网站出现“该页面因服务器不稳定可能无法正常访问”的提示...

    TOC 网站的说法 原文链接 http bbs 360 cn thread 15235172 1 1 html 关于网站出现 该页面因服务器不稳定可能无法正常访问 的提示 近期我们接到一些用户反馈 网站出现 该页面因服务器不稳定可能无法正常
  • Istio是啥?一文带你彻底了解!

    Istio是啥 一文带你彻底了解 什么是 Istio 官方对 Istio 的介绍浓缩成了一句话 An open platform to connect secure control and observe services 翻译过来 就是
  • IDEA快速搭建SpringBoot项目

    项目搭建 创建项目 配置项目信息 依赖选择 可选可不选 根据实际需求来 主要都是后期导入 先选择的话 选择Web下的SpringWeb以及Template Englines下的Thymeleaf就够用了 SQL可以勾选MySQL Drive
  • Android蓝牙连接出现133的解决办法

    代码片段 出现连接133的问题找了很久的解决办法 尝试各种亦然不行 最终的解决办法就是下面标红代码 if status BluetoothGatt GATT SUCCESS if newState gatt STATE CONNECTED
  • redis配置文件详解

    redis配置文件详解 1 开头说明 这里没什么好说的 需要注意的是后面需要使用内存大小时 可以指定单位 通常是以 k gb m的形式出现 并且单位不区分大小写 2 INCLUDES 我们知道Redis只有一个配置文件 如果多个人进行开发维
  • 新建虚拟机与本机ping不通(一招解决)

    初始新建虚拟机或者复制虚拟机后 发现虚拟机能ping通内外网 但是本机无法ping通虚拟机 xshell也无法连接虚拟机 这时候就很头疼了 因为要上传很多文件到虚拟机上面 解决办法 1 关闭虚拟机后 打开虚拟机的虚拟网络编辑器 虚拟机 编辑
  • 抖音直播伴侣使用教程

    抖音直播伴侣使用教程分享 红色框区域 管理场景 添加素材 切换横竖屏 蓝色框区域 常用直播功能 绿色框区域 开关播控制 性能占用情况 官方公告 黄色框区域 直播榜单 白色框区域 弹幕窗口 中央区域 直播画面采集预览 抖音直播伴侣功能介绍 添
  • Vue入门

    npm install g cnpm registry https registry npm taobao org cnpm install global vue cli vue init webpack my project cd my
  • 大厂 H5 开发实战手册

    京东凹凸实验室 Aotu io 英文简称 O2 创立于 2015 年 10 月 为掘金最早一批联合编辑 拥有数千关注者 O2 对内负责京东 PC 端首页 多个频道页 小程序版本京东购物 微信手 Q 京东购物 M 端京东 各类营销活动场景 H
  • Java使用TreeSet来排序学生成绩

    Java TreeSet TreeSet是一个有序的集合 它的作用是提供有序的Set集合 在java中使用 下面我们来进行一个实例来操作一下 具体看看怎么使用 我们的要求是用TreeSet集合存储多个学生对象的姓名 语文和数学成绩 然后按照
  • 一道经典面试题透彻理解面向对象编程思想和简单工厂模式

    一道经典的面试题如下 用一种面向对象编程语言实现一个计算器来满足整数的加减乘除运算 大部分人的代码如下 1 0版本 include