跟我学 Solidity :工厂模式

2021-01-12 11:27:46 浏览数 (1)

  • 译文出自:登链翻译计划[1]
  • 译者:翻译小组[2]
  • 校对:Tiny 熊[3]

欢迎来到学习 Solidity 系列的另一部分。在上一篇文章[4],我们讨论了如何从智能合约中创建另一个智能合约。今天,我们将研究这种情况下的典型用例。

什么是工厂模式?

工厂模式的想法是拥有一个合约(工厂),该合约将承担创建其他合约的任务。在基于类的编程中,此模式的主要动机来自单一职责原则(一个类不需要知道如何创建其他类的实例),并且该模式为构造函数提供了一种抽象。

UML diagram for factory method

图片来自Wikipedia[5].

为什么要在 Solidity 中使用工厂模式?

在 Solidity 中,出于以下原因之一,你可能要使用工厂模式:

如果要创建同一合约的多个实例,并且正在寻找一种跟踪它们并简化管理的方法。

代码语言:javascript复制
contract Factory {
      Child[] children;
      function createChild(uint data){
         Child child = new Child(data);
         children.push(child);
      }
}
contract Child{
     uint data;
     constructor(uint _data){
        data = _data;
     }
}
  • 节省部署成本:你可以先部署工厂,之后在使用时再来部署其他合约。
  • 提高合约安全性(请参阅本文[6]).

如何与已部署的智能合约进行交互

在深入探讨如何实现工厂模式的细节之前,我想澄清一下我们与已部署的智能合约进行交互的方式。工厂模式是用来创建子合约的,并且我们可能希望调用它们的某些函数以更好地管理这些合约。

调用部署的智能合约,需要做两件事:

  1. 合约的 ABI(提供有关函数签名的信息)。如果合约在同一个项目中。你可以使用 import 关键字将其导入。
  2. 部署合约的地址。

举个例子:

代码语言:javascript复制
contract A {
    address bAddress;
    constructor(address b){
       bAddress = b;
    }

    function callHello() external view returns(string memory){
       B b = B(bAddress); // 转换地址为合约类型
       return b.sayHello();
    }
}

contract B {
     string greeting = "hello world";
     function sayHello() external view returns(string memory){
         return greeting;
     }
}

在 Remix 中,首先部署合约 B,然后复制其地址,并在部署时将其提供给 A 的构造函数。现在你可以调用callHello()函数,你将获得合约 B 的sayHello()函数的结果。

普通工厂模式

在此模式下,我们创建具有创建子合约函数的工厂合约,并且可能还会添加其他函数来有效管理这些合约(例如,查找特定合约或禁用合约)。在 create 函数中,我们使用new关键字来部署子合约。

代码语言:javascript复制
contract Factory{
     Child[] public children;
     uint disabledCount;

    event ChildCreated(address childAddress, uint data);

     function createChild(uint data) external{
       Child child = new Child(data, children.length);
       children.push(child);
       emit ChildCreated(address(child), data);
     }

     function getChildren() external view returns(Child[] memory _children){
       _children = new Child[](children.length- disabledCount "");
       uint count;
       for(uint i=0;i<children.length; i  ){
          if(children[i].isEnabled()){
             _children[count] = children[i];
             count  ;
          }
        }
     }

     function disable(Child child) external {
        children[child.index()].disable();
        disabledCount  ;
     }

}
contract Child{
    uint data;
    bool public isEnabled;
    uint public index;
    constructor(uint _data,uint _index){
       data = _data;
       isEnabled = true;
       index = _index;
    }

    function disable() external{
      isEnabled = false;
    }
}

0 人点赞