博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用 Delphi 学设计模式(二) 之 工厂方法篇
阅读量:4452 次
发布时间:2019-06-07

本文共 8155 字,大约阅读时间需要 27 分钟。

“开闭原则”:一个模块应该易于扩展,免于修改

        问题:请考虑上一章的例子中,如果添加一个新的具体水果类“西瓜”需要做哪些工作。

        本章完成以下内容: 

        1、代码用支持中文的 Delphi 2005 编译并通过,并去除了其中一些无关紧要的地方,如异常处理等 ;
        2、重新设计一个情景,分别用“简单工厂模式”和“工厂方法模式”两种方法实现,请体会其中的差别 ;
        3、在情景中添加一个子类后,请体会“简单工厂模式”和“工厂方法模式”两种方法不同的处理方式; 
        4、如果不理解什么是接口、多态、静态函数等概念,这里不作解释,请看第一章或找相关资料; 
        5、本章的情景和上一章差不多,只是把工厂从“果园”变成了“水果小贩”;同样的三种水果:苹果、葡萄、草莓;每种水果都封装了两个逻辑,在和外部“交易”时会用到这两个逻辑。 最后,请重新回顾“开闭原则”

        下面开始吧。。。。。。。

        这里是简单工厂模式的实现方法,在这种模式中: 

        1、一个小贩要负责所有三种水果的交易,这对他来说是很大的挑战噢,不信您看!
        2、顾客必须对水果的名字有一个准确地描述,这样水果才会卖给你,这很影响生意呀!

//简单工厂类和水果类单元文件 

unit SimpleFactory;
interface
type
   接口_水果 = interface(IInterface)
    function 提示():string;
    function 被评价():string;
  end;
   类_苹果 = class(TInterfacedObject, 接口_水果)
    function 提示():string;
    function 被评价():string;
  end;
   类_葡萄 = class(TInterfacedObject, 接口_水果)
    function 提示():string;
    function 被评价():string;
  end;
   类_草莓 = class(TInterfacedObject, 接口_水果)
    function 提示():string;
    function 被评价():string;
  end;
  
   工厂类_小贩 = class(TObject)
  public
    class function 工厂(水果名:string): 接口_水果;
  end;
implementation
{***** 类_苹果 *****}
function 类_苹果.提示():string;
begin
   result:=‘削了皮再吃!’;
end;
function 类_苹果.被评价():string;
begin
   result:=‘恩,还不错,挺甜!’;
end;
{*****类_葡萄 *****}
function 类_葡萄.提示():string;
begin
   result:=‘别把核咽下去了!’;
end;
function 类_葡萄.被评价():string;
begin
   result:=‘没有核呀???’;
end;
{***** 类_草莓 *****}
function 类_草莓.提示():string;
begin
   result:=‘别怪我没告诉你,很酸!’;
end;
function 类_草莓.被评价():string;
begin
   result:=‘试试?哇,牙快酸掉了!’;
end;
{***** 工厂类_小贩 *****}
class function 工厂类_小贩.工厂(水果名:string): 接口_水果;
begin
  if(水果名=‘苹果’)then result:=类_苹果.Create()
  else if(水果名=‘葡萄’)then result:=类_葡萄.Create()
  else if(水果名=‘草莓’)then result:=类_草莓.Create();
end;
end.

 

 

//窗体单元文件 

unit MainForm;
interface
uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls,SimpleFactory;
type
   TForm1 = class(TForm)
     RadioButton1: TRadioButton;
     RadioButton2: TRadioButton;
     RadioButton3: TRadioButton;
    procedure RadioButton3Click(Sender: TObject);
    procedure RadioButton2Click(Sender: TObject);
    procedure RadioButton1Click(Sender: TObject);
  private
    procedure 交易(水果名:string);
  end;
var
   Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.交易(水果名:string);
var
   我买的水果: 接口_水果;
begin
     我买的水果:=工厂类_小贩.工厂(水果名);
     ShowMessage(我买的水果.提示);
     ShowMessage(我买的水果.被评价);
end;
procedure TForm1.RadioButton1Click(Sender: TObject);
begin
   交易(‘苹果’);
end;
procedure TForm1.RadioButton2Click(Sender: TObject);
begin
   交易(‘葡萄’);
end;
procedure TForm1.RadioButton3Click(Sender: TObject);
begin
   交易(‘草莓’);
end;
end.

        这里是工厂方法模式的实现方法,在这种模式中 
        1、每一种水果都对应有一个小贩负责,这样他们做起生意来就轻松多了,呵呵!
        2、顾客直接和小贩打交道,他知道您要什么,这样就不会因为说不清那讨厌的水果名字而吃不上说水果了。

//工厂类和水果类单元文件 

unit FactoryMethod;
interface
type
   接口_水果 = interface(IInterface)
    function 提示():string;
    function 被评价():string;
  end;
   类_苹果 = class(TInterfacedObject, 接口_水果)
    function 提示():string;
    function 被评价():string;
  end;
   类_葡萄 = class(TInterfacedObject, 接口_水果)
    function 提示():string;
    function 被评价():string;
  end;
   类_草莓 = class(TInterfacedObject, 接口_水果)
    function 提示():string;
    function 被评价():string;
  end;
   接口_小贩 = interface(IInterface)
    function 工厂(): 接口_水果;
  end;
   类_苹果小贩 = class(TInterfacedObject, 接口_小贩)
   function 工厂(): 接口_水果;
  end;
   类_葡萄小贩 = class(TInterfacedObject, 接口_小贩)
    function 工厂(): 接口_水果;
  end;
   类_草莓小贩 = class(TInterfacedObject, 接口_小贩)
    function 工厂(): 接口_水果;
  end;
implementation
{****** 类_苹果 ******}
function 类_苹果.提示():string;
begin
   result:=‘削了皮再吃!’;
end;
function 类_苹果.被评价():string;
begin
   result:=‘恩,还不错,挺甜!’;
end;
{****** 类_葡萄 ******}
function 类_葡萄.提示():string;
begin
   result:=‘别把核咽下去了!’;
end;
function 类_葡萄.被评价():string;
begin
   result:=‘没有核呀???’;
end;
{****** 类_草莓 ******}
function 类_草莓.提示():string;
begin
   result:=‘别怪我没告诉你,很酸!’;
end;
function 类_草莓.被评价():string;
begin
   result:=‘试试?哇,牙快酸掉了!’;
end;
{***** 类_苹果小贩 *****}
function 类_苹果小贩.工厂(): 接口_水果;
begin
   result:=类_苹果.Create()
end;
{***** 类_葡萄小贩 *****}
function 类_葡萄小贩.工厂(): 接口_水果;
begin
   result:=类_葡萄.Create()
end;
{***** 类_草莓小贩 *****}
function 类_草莓小贩.工厂(): 接口_水果;
begin
   result:=类_草莓.Create()
end;
end.

//窗体单元文件 

unit MainForm;
interface
uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls,FactoryMethod;
type
   TForm1 = class(TForm)
     RadioButton1: TRadioButton;
     RadioButton2: TRadioButton;
     RadioButton3: TRadioButton;
    procedure RadioButton3Click(Sender: TObject);
    procedure RadioButton2Click(Sender: TObject);
    procedure RadioButton1Click(Sender: TObject);
  private
    procedure 交易(小贩:接口_小贩);
  end;
var
   Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.交易(小贩:接口_小贩);
var
   我买的水果:接口_水果;
begin
     我买的水果:=小贩.工厂();
     ShowMessage(我买的水果.提示);
     ShowMessage(我买的水果.被评价);
end;
procedure TForm1.RadioButton1Click(Sender: TObject);
begin
   交易(类_苹果小贩.Create);
end;
procedure TForm1.RadioButton2Click(Sender: TObject);
begin
   交易(类_葡萄小贩.Create);
end;
procedure TForm1.RadioButton3Click(Sender: TObject);
begin
   交易(类_草莓小贩.Create);
end;
end.
  

        夏天来了,西瓜上市了; 
        在简单工厂模式中,由于只有一个小贩,为了引进西瓜他只好对自己的工厂进行了修改; 
        在工厂方法模式中,由于每个小贩负责一种水果,只需要再引进一个卖西瓜的小贩就行了,对其他小贩的销售不会造成影响 。

下面先看看在简单工厂模式中是怎么做的:

1、在工厂类和水果类单元文件中,引入一个新的西瓜类(这里是扩展,不会影响到已有的代码)

//============================================================================= 

类_西瓜 = class(TInterfacedObject, 接口_水果)
  function 提示():string;
  function 被评价():string;
end;
{****** 类_西瓜 ******}
function 类_西瓜.提示():string;
begin
   result:=‘刚上市的沙瓤大西瓜,2元钱一斤!’;
end;
function 类_西瓜.被评价():string;
begin
   result:=‘靠,被骗了,根本没熟!’;
end;
//=============================================================================

2、在工厂类和水果类单元文件中,修改小贩的工厂方法(这里是修改,已经违反了“开闭原则”)
//============================================================================= 
class function 工厂类_小贩.工厂(水果名:string): 接口_水果;
begin
  if(水果名=‘苹果’)then result:=类_苹果.Create()
  else if(水果名=‘葡萄’)then result:=类_葡萄.Create()
  else if(水果名=‘草莓’)then result:=类_草莓.Create()
  //请注意,下面这条语句是新加上去的,工厂被修改了!!!! 
  else if(水果名=‘西瓜’)then result:=类_西瓜.Create();
end;
//=============================================================================

 

3、在窗体单元文件中,添加一个新的事件处理过程(这里是扩展,不会影响到已有的代码)

//============================================================================= 

RadioButton4: TRadioButton;
procedure RadioButton4Click(Sender: TObject);
procedure TForm1.RadioButton4Click(Sender: TObject);
begin
    交易(‘西瓜’);
end;
//=============================================================================

 

//============================================================================= 

class function 工厂类_小贩.工厂(水果名:string): 接口_水果;
begin
  if(水果名=‘苹果’)then result:=类_苹果.Create()
  else if(水果名=‘葡萄’)then result:=类_葡萄.Create()
  else if(水果名=‘草莓’)then result:=类_草莓.Create()
  //请注意,下面这条语句是新加上去的,工厂被修改了!!!! 
  else if(水果名=‘西瓜’)then result:=类_西瓜.Create();
end;
//=============================================================================

 

3、在窗体单元文件中,添加一个新的事件处理过程(这里是扩展,不会影响到已有的代码)

//============================================================================= 

RadioButton4: TRadioButton;
procedure RadioButton4Click(Sender: TObject);
procedure TForm1.RadioButton4Click(Sender: TObject);
begin
    交易(‘西瓜’);
end;
//=============================================================================

下面再看看在工厂方法模式中是怎么做的: 
1、这一步和在简单工厂模式中做的一样,在工厂类和水果类单元文件中,引入一个新的西瓜类(这里是扩展,不会影响到已有的代码)
//============================================================================= 
类_西瓜 = class(TInterfacedObject, 接口_水果)
  function 提示():string;
  function 被评价():string;
end;
{****** 类_西瓜 ******}
function 类_西瓜.提示():string;
begin
   result:=‘刚上市的沙瓤大西瓜,2元钱一斤!’;
end;
function 类_西瓜.被评价():string;
begin
   result:=‘靠,被骗了,根本没熟!’;
end;
//=============================================================================

2、区别就在这里了,在工厂类和水果类单元文件中,引入一个新的西瓜小贩类(这里是扩展,不会影响到已有的代码)
//============================================================================= 
类_西瓜小贩 = class(TInterfacedObject, 接口_小贩)
  function 工厂(): 接口_水果;
end;
{***** 类_西瓜小贩 *****}
function 类_西瓜小贩.工厂(): 接口_水果;
begin
   result:=类_西瓜.Create()
end;
//=============================================================================

3、在窗体单元文件中,添加一个新的事件处理过程(这里是扩展,不会影响到已有的代码)
//============================================================================= 
RadioButton4: TRadioButton;
procedure RadioButton4Click(Sender: TObject);
procedure TForm1.RadioButton4Click(Sender: TObject);
begin
   交易(类_西瓜小贩.Create);
end;
//=============================================================================

转载于:https://www.cnblogs.com/lzj1981/archive/2013/04/29/3050482.html

你可能感兴趣的文章
SpringAOP用到了什么代理,以及动态代理与静态代理的区别
查看>>
利用STM32CubeMX来生成USB_HID_Mouse工程【添加ADC】(1)
查看>>
【leetcode】Populating Next Right Pointers in Each Node
查看>>
获取请求参数乱码的问题
查看>>
代码实现:判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称...
查看>>
Android客户端测试点
查看>>
Jquery:怎样让子窗体的div显示在父窗体之上
查看>>
01概率
查看>>
.NET LINQ 元素操作
查看>>
Shell脚本
查看>>
MatLab Load cv::Mat 导入数据
查看>>
html+css相关笔记(一)
查看>>
基于块流协议保证音频优先发送
查看>>
关于互联网的一些数据
查看>>
nginx+lua_nginx+GraphicsMagick生成实时缩略图
查看>>
数据预处理:独热编码(One-Hot Encoding)
查看>>
python将对象名的字符串类型,转化为相应对象的操作方法
查看>>
如何删除Dead状态的container
查看>>
【NLP新闻-2013.06.03】New Book Where Humans Meet Machines
查看>>
mongodb安装4.0(rpm)
查看>>