Wrapper pattern

本文介绍了 Delphi 中的 Wrapper 模式,这是一种用于使接口不兼容的类能够协同工作的设计模式。文章通过示例详细讲解了如何利用 Wrapper 模式将一个类包装为另一种接口,特别适用于那些无法修改原始类的情况。

起源

Delphi中的Wrapper模式是在 ‘Adapter’ or ‘Wrapper’ 的基础上上改造的。更多的介绍请查阅[Gam+, pages 139..150]

目的<o:p></o:p>

 <o:p></o:p>

将一个接口转换成客户期待的别外一个接口。Wrappers 模式使得原本由于接口不兼容而不能一起工作类可以一起工作,参阅 [Gam+ 139].

动机<o:p></o:p>

DelphiObject Pascal语言中类对多态性的支持远比接口对多态的支持高。同样意味着两个类虽然可以同时支持一个接口,但它们必须有相同的组先类,从而客户对象可以对类执行动态变换。但有时我们想使一些原本无关的类在一起工作,此时wrapper模式让你将一类包装成另一个类的接口。它类同于多重继承,但在Delphi是一种引用关系。

开始讲述下面的例了,好:

假设您有一个继承自Tobject并想安装到控件板的类:Tsample,但此时必须让组件支持Tcomponent。高兴的是有一种好的办法不用改变Tsample的继承关系就可以将转换成支持<o:p></o:p>

Tcomponent(比如此时你没有类的源码,只有它的BPL包),创建一个继承于Tcomponent的新类TsampleWrapper,并将引用聚合类Tsample。此后类TsampleWrapper将是Tcomponent后代,你可以将它加入控件板了。你现在将Tsample包装成TsampleWrapper的一个成员变量,并为它接供一个专用的访问接口。TsampleWrapper将被委托接受它包装的类的所有行为。这样客户就可能适当的调用Sample的方法及Sample的属性。<o:p></o:p>

另外一种方法使用wrapper pattern关有符合‘Law of Demeter’。些规律的基础是让你不要引用太深的对象。Tsample的访问接口和TsampleWrapper的关系如下:

type

  TSample = class (TObject)

  private

    FSomeValue: Integer;

  public

    function SomeAction(const Data: string): Boolean;

    property SomeValue: Integer read FSomeValue write FSomeValue;

  end;

 <o:p></o:p>

  TSampleWrapper = class (TComponent)

  private

    FSample: TSample;

  public

    property Sample: TSample read FSample;

  end;

依照‘Demeter’s law’访问SampleWrapper.Sample是很好的。但SampleWrapper.Sample.SomeAction却不是好的实例。好的想法是在类TsampleWrapper中定义一个SomeAction方法,并通过SomeAction调度Sample.SomeAction方法。

你可能经常写过这样的代码:ListBox.Canvas.Brush.Color 看起来有点违背 ‘Demeter’s law

应用

上面描述的类演示了一个wrapper模式的应用。类TsampleWrapper聚合Tsample类,并接供了一个Sample的属性接口。现在我们创建一个更完整的wrapped模式的应用,为类TSampleWrapper创建一个叫SomeAction和一个叫SomeValue属性接口,<o:p></o:p>

 <o:p></o:p>

TSampleWrapper = class (TComponent)

  private

    FSample: TSample;

  protected

    function GetSomeValue: Integer;

    procedure SetSomeValue(Value: Integer);

  public

    function SomeAction(const Data: string): Boolean;

»   property Sample: TSample read FSample;

    property SomeValue: Integer read GetSomeValue write SetSomeValue;

  end;

可以看出来了,通过TsampleWrapperSomeAction方法比引用SampleWrapper.Sample.SomeAction更直接。<o:p></o:p>

TsampleWrapper的实现代码如下:(一个可以编译的代码段)

function TSampleWrapper.GetSomeValue: Integer;

begin

  Result := Sample.SomeValue;

end;

 <o:p></o:p>

procedure TSampleWrapper.SetSomeValue(Value: Integer);

begin

  Sample.SomeValue := Value;

end;

 <o:p></o:p>

function TSampleWrapper.SomeAction(const Data: string): Boolean;

begin

  Result := Sample.SomeAction(Data);

end;

说明一下类TsampleWrapper

·      被包装的成员的特性,在包装类中都有着同样的类型,如名称、数据类型,可见性、及其它个别特性。

·      被包装成员的属性也被包装成属性,并且可能通过readwrite方法访问。

·      被包装的成员也接供了属性访问接口,也可能通过readwrite方法访问。

·      事件与被包装起来,通过readwrite方法访问方法,胜于直接访问事件句柄。

·      方法也被包装起来了,并复接被包装类的方法的参数集、现样返回值也是被包装类的返回值。

`timescale 1ps / 1ps (* DowngradeIPIdentifiedWarnings = "yes" *) module axi_10g_ethernet_0_example_design ( // Clock inputs input clk_in_p, // Freerunning clock source input clk_in_n, input refclk_p, // Transceiver reference clock source input refclk_n, output coreclk_out, //LED3 // Example design control inputs input pcs_loopback, input reset, input reset_error, input insert_error, input enable_pat_gen, input enable_pat_check, output serialized_stats, //LED5 input sim_speedup_control, input enable_custom_preamble, // Example design status outputs output frame_error, //LED0 output gen_active_flash, //LED2 output check_active_flash, //LED1 output core_ready, //LED7 output qplllock_out, //LED6 // Serial I/O from/to transceiver output txp, output txn, input rxp, input rxn ); /*-------------------------------------------------------------------------*/ // Set FIFO memory size localparam FIFO_SIZE = 1024; // Signal declarations wire enable_vlan; wire reset_error_sync; wire coreclk; wire block_lock; wire rxrecclk; wire s_axi_aclk; wire tx_dcm_locked; wire tx_s_axis_aresetn; wire tx_s_axis_areset; wire [10:0] s_axi_awaddr; wire s_axi_awvalid; wire s_axi_awready; wire [31:0] s_axi_wdata; wire s_axi_wvalid; wire s_axi_wready; wire [1:0] s_axi_bresp; wire s_axi_bvalid; wire s_axi_bready; wire [10:0] s_axi_araddr; wire s_axi_arvalid; wire s_axi_arready; wire [31:0] s_axi_rdata; wire [1:0] s_axi_rresp; wire s_axi_rvalid; wire s_axi_rready; wire enable_gen_after_config; wire enable_gen_synced; wire tx_statistics_vector; wire rx_statistics_vector; wire [25:0] tx_statistics_vector_int; wire tx_statistics_valid_int; reg tx_statistics_valid; reg [27:0] tx_statistics_shift = 0; wire [29:0] rx_statistics_vector_int; wire rx_statistics_valid_int; reg rx_statistics_valid; reg [31:0] rx_statistics_shift = 0; wire [63:0] tx_axis_tdata; wire [7:0] tx_axis_tkeep; wire tx_axis_tvalid; wire tx_axis_tlast; wire tx_axis_tready; wire [63:0] rx_axis_tdata; wire [7:0] rx_axis_tkeep; wire rx_axis_tvalid; wire rx_axis_tlast; wire rx_axis_tready; wire tx_reset; wire rx_reset; wire tx_axis_aresetn; wire rx_axis_aresetn; wire pat_gen_start; wire resetdone_out; wire [7:0] pcspma_status; wire pcs_loopback_sync; wire enable_custom_preamble_sync; wire enable_custom_preamble_coreclk_sync; wire insert_error_sync; assign coreclk_out = coreclk; // Enable or disable VLAN mode assign enable_vlan = 0; // Synchronise example design inputs into the applicable clock domain axi_10g_ethernet_0_sync_block sync_insert_error ( .data_in (insert_error), .clk (coreclk), .data_out (insert_error_sync) ); axi_10g_ethernet_0_sync_block sync_coreclk_enable_custom_preamble ( .data_in (enable_custom_preamble), .clk (coreclk), .data_out (enable_custom_preamble_coreclk_sync) ); axi_10g_ethernet_0_sync_block sync_pcs_loopback ( .data_in (pcs_loopback), .clk (s_axi_aclk), .data_out (pcs_loopback_sync) ); axi_10g_ethernet_0_sync_block sync_enable_custom_preamble ( .data_in (enable_custom_preamble), .clk (s_axi_aclk), .data_out (enable_custom_preamble_sync) ); assign core_ready = block_lock; // Combine reset sources assign tx_axis_aresetn = ~reset & tx_dcm_locked; assign rx_axis_aresetn = ~reset & tx_dcm_locked; assign tx_s_axis_aresetn = ~reset & tx_dcm_locked; assign pat_gen_start = enable_pat_gen ? enable_gen_synced : 0; // The serialized statistics vector output is intended to only prevent logic stripping assign serialized_stats = tx_statistics_vector || rx_statistics_vector; assign tx_reset = reset; assign rx_reset = reset; //-------------------------------------------------------------------------- // Instantiate a module containing the Ethernet core and an example FIFO //-------------------------------------------------------------------------- axi_10g_ethernet_0_fifo_block #( .FIFO_SIZE (FIFO_SIZE) ) fifo_block_i ( .refclk_p (refclk_p), .refclk_n (refclk_n), .coreclk_out (coreclk), .rxrecclk_out (rxrecclk), .dclk (s_axi_aclk), .reset (reset), .tx_ifg_delay (8'd0), .tx_statistics_vector (tx_statistics_vector_int), .tx_statistics_valid (tx_statistics_valid_int), .rx_statistics_vector (rx_statistics_vector_int), .rx_statistics_valid (rx_statistics_valid_int), .pause_val (16'b0), .pause_req (1'b0), .rx_axis_fifo_aresetn (rx_axis_aresetn), .rx_axis_mac_aresetn (rx_axis_aresetn), .rx_axis_fifo_tdata (rx_axis_tdata), .rx_axis_fifo_tkeep (rx_axis_tkeep), .rx_axis_fifo_tvalid (rx_axis_tvalid), .rx_axis_fifo_tlast (rx_axis_tlast), .rx_axis_fifo_tready (rx_axis_tready), .tx_axis_mac_aresetn (tx_axis_aresetn), .tx_axis_fifo_aresetn (tx_axis_aresetn), .tx_axis_fifo_tdata (tx_axis_tdata), .tx_axis_fifo_tkeep (tx_axis_tkeep), .tx_axis_fifo_tvalid (tx_axis_tvalid), .tx_axis_fifo_tlast (tx_axis_tlast), .tx_axis_fifo_tready (tx_axis_tready), .s_axi_aclk (s_axi_aclk), .s_axi_aresetn (tx_s_axis_aresetn), .s_axi_awaddr (s_axi_awaddr), .s_axi_awvalid (s_axi_awvalid), .s_axi_awready (s_axi_awready), .s_axi_wdata (s_axi_wdata), .s_axi_wvalid (s_axi_wvalid), .s_axi_wready (s_axi_wready), .s_axi_bresp (s_axi_bresp), .s_axi_bvalid (s_axi_bvalid), .s_axi_bready (s_axi_bready), .s_axi_araddr (s_axi_araddr), .s_axi_arvalid (s_axi_arvalid), .s_axi_arready (s_axi_arready), .s_axi_rdata (s_axi_rdata), .s_axi_rresp (s_axi_rresp), .s_axi_rvalid (s_axi_rvalid), .s_axi_rready (s_axi_rready), .xgmacint (), .txp (txp), .txn (txn), .rxp (rxp), .rxn (rxn), .signal_detect (1'b1), .tx_fault (1'b0), .sim_speedup_control (sim_speedup_control), .pcspma_status (pcspma_status), .resetdone_out (resetdone_out), .qplllock_out (qplllock_out) ); //-------------------------------------------------------------------------- // Instantiate the AXI-LITE/DRPCLK Clock source module //-------------------------------------------------------------------------- axi_10g_ethernet_0_clocking axi_lite_clocking_i ( .clk_in_p (clk_in_p), .clk_in_n (clk_in_n), .s_axi_aclk (s_axi_aclk), .tx_mmcm_reset (tx_reset), .tx_mmcm_locked (tx_dcm_locked) ); //-------------------------------------------------------------------------- // Instantiate the AXI-LITE Controller //-------------------------------------------------------------------------- axi_10g_ethernet_0_axi_lite_sm axi_lite_controller ( .s_axi_aclk (s_axi_aclk), .s_axi_reset (tx_s_axis_areset), .pcs_loopback (pcs_loopback_sync), .enable_vlan (enable_vlan), .enable_custom_preamble (enable_custom_preamble_sync), .block_lock (block_lock), .enable_gen (enable_gen_after_config), .s_axi_awaddr (s_axi_awaddr), .s_axi_awvalid (s_axi_awvalid), .s_axi_awready (s_axi_awready), .s_axi_wdata (s_axi_wdata), .s_axi_wvalid (s_axi_wvalid), .s_axi_wready (s_axi_wready), .s_axi_bresp (s_axi_bresp), .s_axi_bvalid (s_axi_bvalid), .s_axi_bready (s_axi_bready), .s_axi_araddr (s_axi_araddr), .s_axi_arvalid (s_axi_arvalid), .s_axi_arready (s_axi_arready), .s_axi_rdata (s_axi_rdata), .s_axi_rresp (s_axi_rresp), .s_axi_rvalid (s_axi_rvalid), .s_axi_rready (s_axi_rready) ); //-------------------------------------------------------------------------- // Add reset synchronizers to the asynchronous reset inputs //-------------------------------------------------------------------------- axi_10g_ethernet_0_sync_reset tx_s_axis_reset_gen ( .clk (s_axi_aclk), .reset_in (~tx_s_axis_aresetn), .reset_out (tx_s_axis_areset) ); axi_10g_ethernet_0_sync_block gen_enable_sync ( .clk (coreclk), .data_in (enable_gen_after_config), .data_out (enable_gen_synced) ); axi_10g_ethernet_0_sync_block reset_error_sync_reg ( .clk (coreclk), .data_in (reset_error), .data_out (reset_error_sync) ); //-------------------------------------------------------------------------- // Instantiate the pattern generator / pattern checker and loopback module //-------------------------------------------------------------------------- axi_10g_ethernet_0_gen_check_wrapper pattern_generator ( .dest_addr (48'hda0102030405), .src_addr (48'h5a0102030405), .max_size (15'd300), .min_size (15'd066), .enable_vlan (enable_vlan), .vlan_id (12'h002), .vlan_priority (3'b010), .preamble_data (56'hD55555567555FB), .enable_custom_preamble (enable_custom_preamble_coreclk_sync), .aclk (coreclk), .aresetn (tx_axis_aresetn), .enable_pat_gen (pat_gen_start), .reset_error (reset_error_sync), .insert_error (insert_error_sync), .enable_pat_check (enable_pat_check), .enable_loopback (!pat_gen_start), .frame_error (frame_error), .gen_active_flash (gen_active_flash), .check_active_flash (check_active_flash), .tx_axis_tdata (tx_axis_tdata), .tx_axis_tkeep (tx_axis_tkeep), .tx_axis_tvalid (tx_axis_tvalid), .tx_axis_tlast (tx_axis_tlast), .tx_axis_tready (tx_axis_tready), .rx_axis_tdata (rx_axis_tdata), .rx_axis_tkeep (rx_axis_tkeep), .rx_axis_tvalid (rx_axis_tvalid), .rx_axis_tlast (rx_axis_tlast), .rx_axis_tready (rx_axis_tready) ); //-------------------------------------------------------------------------- // serialise the stats vector output to ensure logic isn't stripped during // synthesis and to reduce the IO required by the example design //-------------------------------------------------------------------------- always @(posedge coreclk) begin tx_statistics_valid <= tx_statistics_valid_int; if (tx_statistics_valid_int & !tx_statistics_valid) begin tx_statistics_shift <= {2'b01,tx_statistics_vector_int}; end else begin tx_statistics_shift <= {tx_statistics_shift[26:0], 1'b0}; end end assign tx_statistics_vector = tx_statistics_shift[27]; always @(posedge coreclk) begin rx_statistics_valid <= rx_statistics_valid_int; if (rx_statistics_valid_int & !rx_statistics_valid) begin rx_statistics_shift <= {2'b01, rx_statistics_vector_int}; end else begin rx_statistics_shift <= {rx_statistics_shift[30:0], 1'b0}; end end assign rx_statistics_vector = rx_statistics_shift[31]; endmodule 分析这段代码的功能,以及举出代码中的子模块
最新发布
11-22
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值