C++设计模式之一 工厂模式(简单工厂、工厂和抽象工厂)

 

今天开始这个系列之前,心里有些恐慌,毕竟园子里的高手关于设计模式的经典文章很多很多,特别是大侠李会军、吕震宇 老师的文章更是堪称经典。他们的文笔如行云流水,例子活泼生动,讲解深入浅出。好在他们都是用C#描述,也没有提供必要的源码下载,所以我这里用C++实 现。首先我想声明的是我的文笔绝对不如他们的好,例子也没有他们的形象,不过我打算把C++的代码实现和类图提供给大家,就算作为一种补充吧。

   开始设计模式自然而然到提到几个原则:I、开闭法则(OCP);II、里氏代换法则(LSP);III、依赖倒置法则(DIP);IV、接口隔离法则(ISP);V、合成/聚合复用原则(CARP);VI、迪米特法则(LoD),这几个法则在吕震宇 老师的设计模式(二)和设计模式(三)中有非常详尽的阐述和深入浅出的举例分析。有兴趣的朋友打开链接看一下就可以了。

补充说明:

 

  • 我这里所以代码都是用VS2005的C++编译器实现。所以不能保证在其他IDE中能顺利编译,但是我想如果你使用其他编译器,也应该不会有太大问题,主要也应该是stdafx.h文件中包含的头文件问题。
  • 里面出行的结构图都是用微软的Visio2003 绘制,大家下载后可以直接用Visio打开。
  • 在 以后所有的模式例子中都有客户程序,客户程序这个角色不是模式本身的内容,它是模式之外的部分,但是正是这个客户程序完成了对模式的使用,模式本身的结构 是讲解的重点,但是客户程序如何使用模式也是理解模式的一个重要方面,因此在我后续的介绍中都有客户程序这个角色,并会说明究竟调用模式中的哪些角色完成 对模式的使用。

简单工厂模式生活例子 吃饭是人的基本需求,如果人类不需要吃饭,可能我们就能活得清闲许多,也就不需要像现在一样没日没夜的工作,学习。我们学习是为了找到更好的工作,好工作 为了赚更多的钱,最终为了吃饱饭,吃好饭。因此可以说吃饭是与人息息相关,下面就从吃饭的例子来引入工厂模式的学习。

   如果你想吃饭了,怎么办自己做吗?自己做就相当于程序中直接使用new。当然是自己下个指令,别人来做更爽。那就把做饭的任务交给你的老婆吧,那么她就是 一个做饭的工厂了,你告诉她要要吃红烧肉,等会她就从厨房给你端出来一盘香喷喷的红烧肉了,再来个清蒸鱼吧,大鱼大肉不能太多,那就再来个爆炒空心菜,最 后再来个西红柿鸡蛋汤。下图 就是这个问题的模型。
 

显然到了这里,你是Client,你老婆就是工厂,她拥有做红烧肉的方法,做清蒸鱼的方法,做爆炒空心菜、西红柿鸡蛋汤的方法,这些方法返回值就是食物 抽象。红烧肉、清蒸鱼、爆炒空心菜、西红柿鸡蛋汤就是食物的继承类,到这里你就可以大吃二喝了。简单工厂模式也成型了。哈哈,娶一个手艺不错的老婆还真 好,吃的好,吃的爽,又清闲。

   下面来看标准的简单工厂模式的分析。 


意图 把一系列拥有共同特征的产品的创建封装 结构图 
(图2)
角色分析产品基类: 工厂创建的所有产品的基类, 它负责描述所有实例所共有的公共接口。它用来作为工厂方法的返回参数。
代码实现: //---这时一个系列的产品基类

class Product
{
protected:Product(void);
public:virtual ~Product(void);
public:virtual void Function() = 0;
};
//cpp
Product::Product(void)
{
}
Product::~Product(void)
{
}


具体产品类:产品1和产品2,这个角色实现了抽象产品角色所定义的接口。
代码实现: //产品A

class ConcreteProductA :public Product
{
public:ConcreteProductA(void);
public:virtual ~ConcreteProductA(void);
public:virtual void Function();
};
//cpp
ConcreteProductA::ConcreteProductA()
{cout << "创建 A 产品" << endl;
}
ConcreteProductA::~ConcreteProductA()
{cout << "释放 A 产品" << endl;
}
void ConcreteProductA::Function()
{cout << "这是产品 A 具有的基本功能" << endl;
}



//产品B与A类似不这里不再给出,大家可以下载源码

工厂类:负责具体产品的创建,有两种方式实现产品的创建,I、创建不同的产品用不同的方法;II、创建不同产品用相同的方法,然后通过传递参数实现不同产品的创建。本实例中两种模式都给出了,大家自行分析。 
//简单工厂,此类不需要继承,直接硬编码实现生成的产品

class SimpleFactory
{
public:SimpleFactory() {}
public:~SimpleFactory() {}
public:Product *CreateProduct(int ProuctType);Product *CreateProductA();Product *CreateProductB();
};
//CPP
Product * SimpleFactory::CreateProduct(int ProductType = 0)
{Product *p = 0;switch (ProductType){case 0:p = new ConcreteProductA();break;case 1:p = new ConcreteProductB();break;default:p = new ConcreteProductA();break;}return p;
}
Product *SimpleFactory::CreateProductA()
{return new ConcreteProductA();
}
Product *SimpleFactory::CreateProductB()
{return new ConcreteProductB();
}


客户端程序:访问的角色包括产品基类、工厂类。不直接访问具体产品类。通过基类指针的多态实现产品功能的调用。
访问描述:客户程序通过调用工厂的方法返回抽象产品,然后执行产品的方法。 //调用代码

SimpleFactory sf;
Product *p = sf.CreateProductA();
p->Function();
delete p;
p = sf.CreateProductB();
p->Function();
delete p;


优缺点说明优点:

   1) 首先解决了代码中大量New的问题。为何要解决这个问题,好处的说明我想放到结尾总结中。
   2) 用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。 
缺点:对修改不封闭,新增加产品您要修改工厂。违法了鼎鼎大名的开闭法则(OCP)。

附加说明

  • 大家可以参看 吕震宇 老师的C#设计模式(四)参看这个模式的分析,里面还给出了这个模式的两个变体,实现比较简单,有兴趣的朋友可以自行用C++实现一下。
  • 产品基类的代码中构造函数我用了Protected,而没有使用Public,主要是为了体现编码中的一个最小权限原则。说明此类不许用户直接实例化。虽然 这里使用了virtual void Function() = 0;编译器也会控制不让用户直接实例化,不过我依然认为使用私有化构造函数来保护类不直接实例化是一个良好的编程风格。

 


工厂方法模式生活例子:    人是最贪得无厌的动物,老婆手艺再好,总有不会做的菜,你想吃回锅肉,怎么办,让老婆学呗,于是就给她就新增了做回锅肉的方法,以后你再想吃一个新菜,就 要给你老婆新加一个方法,显然用老婆做菜的缺点也就暴露出来了,用程序设计的描述就是对修改永远不能封闭。当然优点也是有的,你有了老婆这个工厂,这些菜 不用你自己做了,只要直接调用老婆这个工厂的方法就可以了。 

   面对上面对修改不能封闭的问题,有没有好的解决方案吗,如果你有钱,问题就迎刃而解了,把老婆抽象变成一个基类,你多娶几个具体的老婆,分别有做鱼 的,做青菜的,炖汤的老婆,如果你想吃一个新菜,就再新找个女人,从你的老婆基类继承一下,让她来做这个新菜。显然多多的老婆这是所有男人的梦想,没有办法,法律不允许,那么咱们只是为了做饭,老婆这个抽象类咱们不叫老婆了,叫做厨师吧,她的子类也自然而然的该叫做鱼的厨师、炖汤的厨师了。现在来看这个模式发生了变化,结构中多了一个厨师的抽象,抽象并不具体的加工产品了,至于是炖汤还是炖鱼,是由这个抽象工厂的继承子类来实现,现在的模式也就变成工厂方法模式了,这个上面的结构图就变成了下图的结构了。
 

       现在再来分析现在的模式,显然简单工厂的缺陷解决了,新增加一个菜只需要新增加一个厨师就行了,原来的厨师还在做原来的工作,这样你的设计就对修改封 闭了。你看把老婆解放出来,招聘大量的厨师到你家里这个方案多么的完美,你老婆也会爱死你了。当然前提就是你要有多多的钱噢,当然这里的钱的多少在软件领域应该看你的客户软件投资方的要求。 
下面来一下标准的工厂模式的实现意图

 

  • 定义一个用户创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
  • 上面是GOF关于此模式的意图描述,我想补充的是您可以这样理解:为了改善简单工厂对修改不能关闭的问题。

结构

图4
角色分析产品基类:同简单工厂的产品基类,其实就是用和简单工厂中的是同一个类,这里并没有重写。
具体产品类:也是用的简单工厂的具体产品类,为了体现对修改的关闭这里为系统新添加了一个具体产品类,就是“新产品”,代码中叫做“ConcreteProductANew”
工厂基类:定义了工厂创建产品的接口,但是没有实现,具体创建工作由其继承类实现。
代码实例 
//工厂模式,此模式的工厂只定义加工产品的接口,具体生成交予其继承类实现
//只有具体的继承类才确定要加工何种产品

class Factory
{
public:Factory(void);
public:virtual ~Factory(void);
public:virtual Product* CreateProduct(int ProductType = 0) = 0;
};
//CPP
Factory::Factory(void)
{
}
Factory::~Factory(void)
{
}


具体工厂类:工厂基类的具体实现,由此类决定创建具体产品,这里 ConcreteFactory1 对于与图中的 工厂实现ConcreteFactory2 对于与图中的新工厂
下面给出实现代码

//工厂实现
class ConcreteFactory1 :public Factory
{
public:ConcreteFactory1();
public:virtual ~ConcreteFactory1();
public:Product* CreateProduct(int ProductType);
};
//新工厂,当要创建新类是实现此新工厂
class ConcreteFactory2 :public Factory
{
public:ConcreteFactory2();
public:virtual ~ConcreteFactory2();
public:Product* CreateProduct(int ProductType);
};
//CPP
ConcreteFactory1::ConcreteFactory1()
{
}
ConcreteFactory1::~ConcreteFactory1()
{
}
Product * ConcreteFactory1::CreateProduct(int ProductType = 0)
{Product *p = 0;switch (ProductType){case 0:p = new ConcreteProductA();break;case 1:p = new ConcreteProductB();break;default:p = new ConcreteProductA();break;}return p;
}
ConcreteFactory2::ConcreteFactory2()
{
}
ConcreteFactory2::~ConcreteFactory2()
{
}
Product * ConcreteFactory2::CreateProduct(int ProductType = 0)
{return new ConcreteProductANew();
}



客户端调用:访问角色(产品基类、工厂基类、工厂实现类)
调用描述:客户程序通过工厂基类的方法调用工厂实现类用来创建所需要的具体产品。从而实现产品功能的访问。
代码实现

Factory*fct = new ConcreteFactory1();
Product *p = fct->CreateProduct(0);
p->Function();
delete p;
p = fct->CreateProduct(1);
p->Function();
delete p;
delete fct;
fct = new ConcreteFactory2();
p = fct->CreateProduct();
delete p;
delete fct;


优缺点分析优点

  • 简单工厂具有的优点
  • 解决了简单工厂的修改不能关闭的问题。系统新增产品,新增一个产品工厂即可,对抽象工厂不受影响。

缺点:对于创建不同系列的产品无能为力 适用性

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

其他参考

  • 吕震宇的C#设计模式(5)-Factory Method Pattern
  • TerryLee 的.NET设计模式(5):工厂方法模式(Factory Method)


抽象工厂模式生活例子世事多变,随着时间的推移,走过的地方越来越多,你天南海北的朋友也越来越多。你发现菜原来还分了许多菜系,鲁菜、粤菜、湘菜等等,它们各有各的风味,同样是红烧肉由不同菜系出来的味道也各不相同, 你招待不同的朋友要用不同的菜系,这下难办了,你的厨师都是鲁菜风味,怎么办,广东的朋友来了吃不惯。现在我们再回到简单工厂模式(就是老婆做菜的模式),我们把红烧肉再向下继承,生成鲁菜红烧肉、粤菜红烧肉、湘菜红烧肉;清蒸鱼向下继承为鲁菜清蒸鱼、粤菜清蒸鱼、湘菜清蒸鱼,其它也以此类推。我们也 修改一下老婆的这个类,不让其返回食物基类,而是返回红烧肉、清蒸鱼、爆炒空心菜、西红柿鸡蛋汤这一层次,并把这些方法抽象化,作为菜系工厂基类,然后再 从此基类继承出,鲁菜工厂、粤菜工厂、湘菜工厂等等,再由这些具体工厂实现创建具体菜的工作,哈哈你如果招待广东朋友就用粤菜工厂,返回的就是一桌粤菜菜 系的红烧肉、清蒸鱼、空心菜和西红柿鸡蛋汤了,你的广东朋友一定会吃的非常合乎胃口了。噢,非常好,你已经实现了抽象工厂模式了。结构模型图也变成了下图 6)的样子了。

(图6)
       现在可以看到,想新来做一个菜系,只需新聘请一个厨师就可以了,多么完美,但是你先别高兴太早,如果你想新增加一个菜就变得非常困难了。
意图 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。 
结构

角色分析产品基类:这里包含产品基类A和产品基类B,实际上在我的示例代码中,这两个产品都从共同的基类继承而来,但是这个继承关系却是在这个模式之外的部分,而本身这个模式关心的是这两个产品基类的差异部分。 
代码实现:这里的代码就是借用的简单工厂模式中具体产品类的代码实现部分,为了大家阅读方便,下面重新给出一下。

//产品A
class ConcreteProductA :public Product
{
public:ConcreteProductA(void);
public:virtual ~ConcreteProductA(void);
public:virtual void Function();
};
//cpp
ConcreteProductA::ConcreteProductA()
{cout << "创建 A 产品" << endl;
}
ConcreteProductA::~ConcreteProductA()
{cout << "释放 A 产品" << endl;
}
void ConcreteProductA::Function()
{cout << "这是产品 A 具有的基本功能" << endl;
}



//产品B与A类似不这里不再给出,大家可以下载源码


具体产品类:这里的具体产品类是产品A1,A2,B1、B2等,
代码实现:A1对应的实现就是“”

class ConcreteProductA1 :public ConcreteProductA
{
public:ConcreteProductA1(void);
public:virtual ~ConcreteProductA1(void);
public:virtual void Function();
};
//CPP
ConcreteProductA1::ConcreteProductA1()
{cout << "创建 A1 产品" << endl;
}
ConcreteProductA1::~ConcreteProductA1()
{cout << "释放 A1 产品" << endl;
}
void ConcreteProductA1::Function()
{cout << "这时产品 A1 具有的基本功能" << endl;
}


工厂抽象接口:定义了创建产品的接口,这里返回参数是返回的产品A,产品B,而本身产品A和B的共同基类,小弟认为正是这个特征构成了抽象工厂和工厂模式的区别。
代码实现

//抽象工厂模式
class AbstractFactory
{
public:AbstractFactory();
public:virtual ~AbstractFactory();
public:virtual ConcreteProductA* CreateA() = 0;virtual ConcreteProductB* CreateB() = 0;
};
//CPP
AbstractFactory::AbstractFactory()
{
}
AbstractFactory::~AbstractFactory()
{
}




具体工厂实现类:工厂1和工厂2。新增加系列,只需新实现一个工厂。
代码实现: 工厂1的就是ConcreteAbsFactory1,工厂2的代码类似,这里没有给出,可以在下载代码中看到

工厂1-----
class ConcreteAbsFactory1 :public AbstractFactory
{
public:ConcreteAbsFactory1();
public:virtual ~ConcreteAbsFactory1();
public:virtual ConcreteProductA* CreateA();virtual ConcreteProductB* CreateB();
};
//CPP
ConcreteAbsFactory1::ConcreteAbsFactory1()
{
}
ConcreteAbsFactory1::~ConcreteAbsFactory1()
{
}
ConcreteProductA* ConcreteAbsFactory1::CreateA()
{return new ConcreteProductA1();
}
ConcreteProductB * ConcreteAbsFactory1::CreateB()
{return new ConcreteProductB1();
}




客户端访问: 访问角色(产品基类、抽象工厂、具体工厂实现类)
访问描述: 通过抽象工厂的指针访问具体工厂实现来创建对应系列的产品,然后通过产品基类指针访问产品功能。
调用代码:

AbstractFactory *absfct = new ConcreteAbsFactory1();
ConcreteProductA *cpa = absfct->CreateA();
cpa->Function();
delete cpa;
ConcreteProductB *cpb = absfct->CreateB();
cpb->Function();
delete cpb;
delete absfct;
absfct = new ConcreteAbsFactory2();
cpa = absfct->CreateA();
cpa->Function();
delete cpa;
cpb = absfct->CreateB();
cpb->Function();
delete cpb;



和工厂模式的分析比较    现在可以和工厂模式对比一下,抽象工厂返回的接口不再是产品A和产品B的共同基类Product了,而是产品A、产品B基类(在工厂模式中它们为具体实现 类,这里变成了基类)了。此时工厂的抽象和简单工厂中的工厂方法也很类似,就是这些特征区使其别于工厂模式而变成抽象工厂模式了,因此抽象工厂解决的是创 建一系列有共同风格的产品(鲁菜还是粤菜),而工厂方法模式解决的创建有共同特征的一系列产品(红烧肉、清蒸鱼它们都是食物)。当然简单工厂的缺陷在抽象 工厂中又再次出现了,我要新增加一个产品,工厂抽象接口就要改变了。因此抽象工厂并不比工厂模式完美,只不过是各自的适用领域不同而已。其实,这里如果把 抽象工厂模式的接口返回产品A和产品B的共同基类(工厂模式返回的参数),你会发现,奇怪这个模式怎么这么眼熟,它不是恰恰退化成工厂模式了。
类模式与对象模式的区别讨论:先看定义类“模式使用继承关系,把对象的创建延迟的子类,对象模式把对象的创建延迟到另一个对象中”。 分析:首先它们创建对象都不是在基类中完成,都是在子类中实现,因此都符合类模式的概念;但是工厂模式的创建产品对象是在编译期决定的,要调用某个工厂固 定的,而抽象工厂模式对产品的创建是在运行时动态决定的,只有到运行时才确定要调用那个工厂,调用工厂随运行环境而改变。(这里我一直很混乱,欢迎大家讨 论)
适用性

  • 一个系统要独立于它的产品的创建、组合和表示时
  • 一个系统要由多个 产品系列中的一个来配置时
  • 当你要强调一个系列相关的产品对象的设计以便进行联合使用时
  • 当你提供一个产品类库,而只想显示它们的接口而不是实现时。

参考

  • 吕震宇的C#设计模式(6)
  • TerryLee 的.NET设计模式(3):抽象工厂模式(Abstract Factory)

总结    工厂本质就是用工厂方法替代直接New来创建对象。这里不是指的让用户重载一个新操作符号来进行创建对象的操作,而是说把New 操作封装在一个方法中,等用户需要创建对象时调用此方法而避免直接使用New而已。这样做的目的就是之一就是封装,避免代码中大量New的运算符,这当然 不是主要目的,因为这样虽然New少了,CreateObject方法却多了,但是如果产品类的构造函数变了,我想常用工厂模式的修改源代码的工作应该简 便许多吧,当然这算不上这个模式的好处,它的真正强大的功能其实在于适应变化,这也是整个设计模式最根本的目的;还有一点就是体现了抽象于实现的分离,当 然创建型模式都具有这个特点,工厂模式非常明显吧了,把具体创建工作放置到工厂中,使客户端程序更专注与业务逻辑的,这样的代码结构也更进行合理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/436147.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】Windows消息传递机制详解

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka Windows是一个消息&#xff08;Message&#xff09;驱动系统。Windows的消息提供了应用程序之间、应用程序与Windows系统之间进行通信的手段。应用程序想要实现的功能由消息来触发&#xff0c;并且靠对消…

设计模式C++实现(2)——单例模式

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性&#xff1a;封装、继承、多态&#xff0c;真正领悟设计模式的精髓是可能一个漫长的过程&#xff0c;需要大量实践经验的积累。最近看设计模式的书&#xff0…

设计模式C++实现(3)——建造者模式

软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。设计模式中运用了面向对象编程语言的重要特性&#xff1a;封装、继承、多态&#xff0c;真正领悟设计模式的精髓是可能一个漫长的过程&#xff0c;需要大量实践经验的积累。最近看设计模式的书&#xff0…

宽字符串忽略大小写比较的实现(原)

宽字符串忽略大小写比较的实现(原) 孙文涛 2008-07-24 在Mac机器平台上没有wcsicmp 或 wcscasecmp之类的函数实现对宽字符忽略大小写的比较&#xff0c;所以实现了好几种方法。 一个自然的思路是: (1) wcscpy 原字符串到tmp字符串; (2) tolower tmp字符串; (3) 然后调用仅存的w…

有关JAVA考试中数据库的题,javaee期末考试题库,用javaEE编写一个题库系统,要怎么做...

javaEE数据库简单问题。你插入2113数据库的时候是把5261它封装为一4102个对象插入的吗&#xff1f;1653如果封装为一个User对象版的权话(User对象有ID和LEVEL两个属性)ResultSet rs ps.executeQuery();User user new User();if(rs.hasNext()){user rs.next();}关于javaee 中j…

oracle 12c sql图形化,Oracle 12c PL/SQL程序设计终极指南

Oracle 12c PL/SQL程序设计终极指南作者&#xff1a;孙风栋;王澜;郭晓惠出版日期&#xff1a;2015年06月文件大小&#xff1a;11.73M支持设备&#xff1a;&#xffe5;60.00在线试读适用客户端&#xff1a;言商书局iPad/iPhone客户端&#xff1a;下载 Android客户端&#xff1a…

oracle 存储同步,Oracle数据库知识——存储过程篇

在线QQ客服&#xff1a;1922638专业的SQL Server、MySQL数据库同步软件存储过程是一组用于完成特定功能的SQL语句&#xff0c;该语句已编译并存储在数据库中。用户通过指定存储过程的名称并提供参数(如果存储过程具有参数)来执行它。存储过程是数据库中的重要对象。任何设计良好…

使用MvcContrib的FormHelper

MvcContrib的FormHelper提供了三大Helper Html辅助 验证HelperGrid表格Helper下载 下载后将MvcContrib.dll与MvcContrib.Samples.FormHelper.dll引用到Asp.net MVC工程 在Web.Config pages.namespaces加入以下节点 <add namespace"MvcContrib.UI.Tags"/><ad…

WinCE控制面板添加应用程序

WinCE系统中的控制面板和Windows系统中的控制面板原理是一样的&#xff0c;里面就是包含了一些应用程序。WinCE系统的控制面板由Ctlpnl.exe&#xff0c;Control.exe和一些.cpl文件组成&#xff0c;其中Ctlpnl.exe和Control.exe用于控制控制面板的文件夹显示和架构&#xff0c;而…

oracle 游标 904,如何解决Oracle数据库游标连接超出问题

如何解决Oracle数据库游标连接超出问题发布时间&#xff1a;2020-07-21 10:57:35来源&#xff1a;亿速云阅读&#xff1a;103作者&#xff1a;小猪这篇文章主要讲解了如何解决Oracle数据库游标连接超出问题&#xff0c;内容清晰明了&#xff0c;对此有兴趣的小伙伴可以学习一下…

用多媒体库 Bass.dll 播放 mp3 [15] - 设置与获取播放速度

本例效果图:代码文件:unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ComCtrls;typeTForm1 class(TForm)OpenDialog1: TOpenDialog;Button1: TButton;Button2: TButton;Button3: TButton;TrackBar1:…

【转】Dicom文件解析!!!!!!

转自&#xff1a;https://blog.csdn.net/leaf6094189/article/details/8510325 Dicom全称是医学数字图像与通讯&#xff0c;这里讲的暂不涉及通讯那方面的问题 只讲*.dcm 也就是diocm格式文件的读取&#xff0c;读取本身是没啥难度的 无非就是字节码数据流处理。只不过确实比较…

VS2008 JS脚本调试总是调试旧代码 真不知道怎么回事?谁能帮帮我呀!

如图,[dynamic]标记的是调试的元文件 xml1.htm[dynamic]和xml.js[dynamic] 我更改后的文件是xml1.htm和xml.js,见图1 2 调试的文件有debugger 更改后的文件我把debugger注了 js脚本中我把变量给改了见3 4 ,所以在浏览新的xml1.htm时,竟然报对象找不到,真实受不了了!!! 为什么我…

【转】C#开发PACS医学影像处理系统(一):开发背景和功能预览

转自&#xff1a;https://www.cnblogs.com/Uncle-Joker/p/13646949.html 本系列文章将从以下模块和大家分享和讨论使用C#开发医学软件PACS和RIS系统&#xff0c; 国内相关资料比较少&#xff0c;也借此机会丰富一下医学软件开发生态&#xff0c;讨论技术难点&#xff0c;希望…

《WF编程》系列之30 - 基本活动:错误处理

《WF编程》系列之30 - 基本活动:错误处理 4.3 错误处理 Fault,故障,现在官方已经将其翻译为错误,那么以后的随笔中我也就采用官方的翻译吧. 错误处理也属于流程控制的一部分,这一节我来介绍一下有关错误处理的活动.错误是指在工作流执行期间发生的异常.我们可以使用错误处理程…

oracle错误27101,ORA-27101ORA-01034错误解决

Oracle已经启动&#xff0c;连接sqlplus后&#xff0c;进行查询&#xff0c;出现下面错误ORA-01034: ORACLE not availableORA-27101: shared memory realm doesOracle已经启动&#xff0c;连接sqlplus后&#xff0c;进行查询&#xff0c;出现下面错误ORA-01034: ORACLE not av…

NOD32升级ID获取器For流星无语更新了

NOD32升级ID获取器For流星无语更新了一下,现在可以直接把用户名密码写入注册表了,连复制/粘贴操作都可以免了...转载于:https://www.cnblogs.com/lxwy/archive/2008/09/05/4420722.html

【转】【C#】使用fo-dicom完成BMP,JPG,PNG图片转换为DICOM文件

转自&#xff1a;https://developer.aliyun.com/article/672065 最近研究了一下DICOM和BMP文件转换的问题&#xff0c;也是很头大。度娘了很久&#xff0c;也在CSDN等论坛看到一些断断续续的文件&#xff0c;最主要的是代码只是片断&#xff0c;不是完整的实现。头大了。 首先…

C++设计模式之二 AbstractFactory模式

设计模式的目的就是尽量减少“变化”对程序的影响&#xff0c;尤其是对客户程序的影响。AbstractFactory模式作为创建型模式的一种&#xff0c;解决的就是“new”在变化中可能引起的问题。 先来看看new有何种不好&#xff0c;举个创建汽车的车门的例子&#xff1a; 很自然的一…

改写DataCogs在MOSS列表中实现三级联动字段

项目中有需求需要实现列表中3级的字段联动。参照小熊的[分享]修复DataCogs二级联动FieldControl支持中文 &#xff0c;改造一下&#xff0c;实现了3级联动字段。另外&#xff0c;还可以实现一个列表中同时有两个&#xff0c;或两个以上互相独立的联动字段&#xff0c; 详细的字…