【问题标题】:Method Dependencies - Best Practices?方法依赖——最佳实践?
【发布时间】:2012-10-09 09:34:09
【问题描述】:

处理方法执行所依赖的属性的最佳方式是什么?

假设您有一个具有 2 个属性的类和一个对这 2 个属性执行某些操作的方法。实例化类,设置属性,然后执行方法会更好(不带参数);还是实例化类,然后执行方法,传入将设置属性的参数?

例如:

class Person ...
    string Name ...
    string Address ...
    void Save() {
        Database.SavePerson(this.Name, this.Address);
    }

--- 或 ---

class Person ...
        string Name ...
        string Address ...
        void Save(string name, string address) {
            this.Name = name;
            this.Address = address;
            Database.SavePerson(this.Name, this.Address);
        }

在第一个示例中,如果在调用 Save 方法之前尚未设置 Name 和 Address,则会出现错误。因此,您似乎必须验证这些属性是否已在方法中设置。

第二个示例强制用户提供执行该方法所需的数据。但是,这似乎有点多余,因为传入的参数已经是对象的属性。

有没有“最好”的方法来做到这一点?

提前致谢。

【问题讨论】:

  • “最佳”方式是对您的用例更有意义的方式。
  • 毫无疑问,你的第二个例子是一个不好的方法。

标签: c# .net oop dependencies


【解决方案1】:

只有在参数可以以某种方式推断/解析,或者它们永远不会改变时,才让方法无参数。

否则它会变成一个可怕的leaky abstraction,您需要了解该方法的工作原理才能使用它。

【讨论】:

    【解决方案2】:

    首先我会考虑让实体负责自己的持久性是否是您想要的设计。

    如果不是,则 Person 实体将公开属性,而另一种类型将负责保存该 Person 实体(例如,如果使用类似 Repository 模式的东西,就会出现这种情况)。

    如果实体负责持久化自身(如果您使用丰富的域模型,例如与 CSLA 等框架一起使用的模型),那么您将只有一个无参数的 Save 方法,并且如果需要这些属性,那么某种形式的验证框架会捕捉到任何缺失的要求。

    【讨论】:

      【解决方案3】:

      就我个人而言,我两者都不会。您的第一个示例类似于 Active Record,而第二个示例对我来说根本没有意义,如果函数接受参数,那么拥有字段/属性有什么意义?

      这两种方法的问题是Person 类公开了您可能不想要的数据库逻辑。

      我要做的是使用存储库模式:

      public class Person
      {
          public string Name { get; set; }
          public string Address { get; set; }
      }
      
      public class PersonRepository()
      {
          public void Add(Person person)
          {
              // do some database stuff
          }
      }
      
      // ...
      
      Person person = new Person() { Name = "Jim", Address = "123 Fake Street" };
      
      PersonRepository personRepository = new PersonRepository();
      personRepository.Add(person);
      

      【讨论】:

        【解决方案4】:

        要么你有一个实例方法,它会自动使用它自己的不带参数的属性,要么你有一个静态方法,可以接受任何传递给它的参数

        public class Person
        {
            public string Name { get; set; }
            public string Address { get; set; }
        
            public void Save()
            {
                Database.SavePerson(Name, Address);
            }
        
            public static void Save(string name, string address)
            {
                Database.SavePerson(name, address);
            }
        }
        

        对象的一般概念是每个对象都对自己的数据负责。但是,一个类可以有一个可以全局使用的静态方法,并且不绑定到任何对象实例。静态方法不能访问实例成员。


        但基本问题是是否应该在 Person 类中包含保存方法。相反,我会将Database.SavePerson 方法的参数列表更改为

        public static void SavePerson(Person person) { ... }
        

        并像这样使用它

        var p = new Person { Name = "John", Address = "Wall Street, NY" };
        Database.SavePerson(p);
        

        【讨论】:

          【解决方案5】:

          我想到了什么——你用这种方法破坏了Single Responsibility Principle。因为您做了三件事 - 持久化实体、重命名人员和更改其地址。这从方法的名称中不清楚。这是副作用。

          因此,为了让开发人员了解您的方法的真正用途,您应该将其重命名为 SaveAndRenameAndRelocate。名字不是很好?同意。

          因此,我创建了将实体保存在当前状态的无参数方法。

          public void Save()
          {
             // code, which should be somewhere in repository
          }
          

          如果您需要重命名人员 - 通过 Name 属性进行。如果您需要更改地址 - 通过地址属性进行。如果不允许保存没有姓名和/或地址的人 - 通过构造函数初始化这些属性:

          public Person(string name, string address)
          {
             // null-check goes here
             Name = name;
             Address = address;
          }
          

          顺便说一句,让实体保持自身并不是一个好主意:)

          【讨论】:

            猜你喜欢
            • 2011-06-11
            • 2010-12-11
            • 2015-07-29
            • 2011-10-15
            • 1970-01-01
            • 2022-08-09
            相关资源
            最近更新 更多