if(type == DRIVE_CDROM) //如果是光驱的话 cout<<\驱动器\是光驱\\n\ } cin.ignore(); return 0; }
(3) 编译运行你的程序。 3. 编程练习:
(1) 请使用WindowsAPI编程,读取主机(本机)的主机名和IP地址。
提示:用于获取本机的API函数是 #include
int PASCAL FAR gethostname(char FAR *name, int namelen);
而gethostbyname()函数返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针
truct hostent FAR* PASCAL FAR gethostbyname(const char FAR * name);
上机指导9 常用设计模式编程练习
目的和要求:
1. 掌握单例模式的基本用法。
2. 掌握简单工厂模式或者工厂模式的基本用法。 3. 初步掌握常用设计模式的基本概念和优缺点。 内容和步骤:
1. 单例模式编程练习:模拟实现简易打印池程序
(1) 要求:打印池(Print Spooler)是一个用于管理打印任务的应用程序,通过打印池
用户可以删除、中止或者改变打印任务的优先级,在一个系统中只允许运行一个打印池对象,如果重复创建打印池则抛出异常。请用单例模式实现一个简易的打印池程序。
(2) 单例模式的目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。基
本的单例模式C++实现代码如下所示(仅供参考): class CSingleton {
//其他成员 public:
static CSingleton* GetInstance() {
if ( m_pInstance == NULL ) //判断是否第一次调用 m_pInstance = new CSingleton(); return m_pInstance; }
private:
CSingleton(){};
34
static CSingleton * m_pInstance; };
该模式中包含一个静态私有成员变量与静态公有的工厂方法,该工厂方法负责检验实例的存在性并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。 (3) 现在请你参考上面所示的基本的单例模式,编程实现打印池类的定义和实现。该类
的类图如下所示:
PrintSpoolerSingleton - instance : PrintSpoolerSingleton - PrintSpoolerSingleton () + getInstance () : PrintSpoolerSingleton + manageJobs () : void ... instance PrintSpoolerException + PrintSpoolerException (String message) ... (4) 请编写测试用的主程序,测试是否能够实例化多个打印池对象。 (5) 现在请回答以下问题:
a) 单例模式类中,构造函数为什么需要定义为私有属性?例如,PrintSpoolerSingleton
类的构造函数就是私有的。
b) 仔细阅读单例模式CSingleton,大家可能存在一个疑问:m_pInstance指向的空间
什么时候释放呢?更严重的问题是,这个实例的析构操作什么时候执行? 要解决这个问题,在C++中通常的做法如下: class CSingleton: { // 其它成员 public:
static CSingleton * GetInstance() private:
CSingleton(){};
static CSingleton * m_pInstance;
class CGarbo // 它的唯一工作就是在析构函数中删除CSingleton的实例 {
public:
~CGarbo()
35
{
if (CSingleton::m_pInstance)
delete CSingleton::m_pInstance; } };
static CGarbo Garbo;
// 定义一个静态成员,在程序结束时,系统会调用它的析构函数 };
现在要你回答的问题是:为什么采用定义静态成员的方式释放静态成员空间,而不是在析构函数中进行?
2. 简单工厂模式编程练习:计算器
(1) 要求:请把上机指导1中你实现的计算器(两个操作数的加减乘除运算),增加简单
工厂模式类,以降低你的计算器程序在扩展新的运算符时尽可能降低修改代价。
(2) 在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定
义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。 下面是简单工厂模式的参照代码:
//算法的父类,抽象出返回结果的接口 class Operation {
public:
virtual int GetResult() =0; public:
double m_Num1; double m_Num2; };
//工厂类,用于生产相应的算法子类 class OperationFactry {
public:
OperationFactry(void); ~OperationFactry(void); public:
static Operation* CreateOperate(int n ) {
switch(n) {
case 1:
return new OperationAdd; break; } } };
//算法子类,由工厂类创建,重写父类中的虚函数 class OperationAdd
36
{
public:
int GetResult(); };
(3) 现在请上机重新实现计算器程序,按照以下的类图定义运算基类、运算子类(加法
类、减法类、乘法类、除法类)、简单工厂类:
(4) 请编写测试用的主程序,并运行你的程序。
(5) 下面在上面调试通过的程序基础上,增加第五个运算子类(乘方),并重新调试运行
程序?
现在请思考问题:用或者不用简单工厂模式,增加新的运算子类时,两种方式修改代价有什么不同吗?
37