有条件地限制财产访问

时间:2010-12-10 14:47:45

标签: c# oop design-patterns

是否有更好的方法来限制对职业和雇主财产的访问?

本课程旨在收集一个人(潜在客户)的就业信息。 EmploymentStatus可以就业,自雇,失业,退休等......

我只希望这个班级的用户能够设置雇主和职业,如果这个人确实受雇了。

public class EmploymentInformation
{
    private const string _EmploymentStatusNotEmployedMessage = "Employment status is not set to employed";

    private string _occupation;

    private Company _employer;

    /// <summary>The person's employment status<example>Employed</example></summary>
    public EmploymentStatus EmploymentStatus { get; set; }

    /// <summary>The person's occupation<example>Web Developer</example></summary>
    public string Occupation
    {
        get
        {
            if (IsEmployed)
            {
                return _occupation;
            }
            throw new ApplicationException(_EmploymentStatusNotEmployedMessage);
        }

        set
        {
            if (IsEmployed)
            {
                _occupation = value;
            }
            throw new ApplicationException(_EmploymentStatusNotEmployedMessage);
        }
    }

    /// <summary>The person's employer</summary>
    public Company Employer
    {
        get
        {
            if (IsEmployed)
            {
                return _employer;
            }
            throw new ApplicationException(_EmploymentStatusNotEmployedMessage);
        }

        set
        {
            if (IsEmployed)
            {
                _employer = value;
            }
            throw new ApplicationException(_EmploymentStatusNotEmployedMessage);
        }
    }

    private bool IsEmployed
    {
        get
        {
            return EmploymentStatus == EmploymentStatus.Employed 
                || EmploymentStatus == EmploymentStatus.SelfEmployed;
        }
    }

    /// <summary>
    /// Constructor for EmploymentInformation
    /// </summary>
    /// <param name="employmentStatus">The person's employment status</param>
    public EmploymentInformation(EmploymentStatus employmentStatus)
    {
        EmploymentStatus = employmentStatus;
    }
}

7 个答案:

答案 0 :(得分:2)

如果没有设置值,只返回null有什么问题吗?这是相当普遍的做法。如果Employer不存在,则其值为null。为什么它null可能不相关。此外,强制将就业状态设定在班级本身的范围内。

答案 1 :(得分:2)

强制开发人员按特定顺序设置属性是一个危险的设计:它会使界面误导并鼓励错误。

相反,请考虑使EmploymentInformation个对象不可变:

// Constructor for retired / unemployed people
public class EmploymentInformation(EmploymentStatus status) {}

// Constructor for self-employed people - we know their status
public class EmploymentInformation(string occupation) {}

// Constructor for people employed by others - we know their status
public class EmploymentInformation(string occupation, Company employer) {}

public bool IsEmployed { get; }
public string Occupation { get; }
public Company Employer { get; }

答案 2 :(得分:1)

首先,如果没有EmploymentInformation,为什么可以构建Employer的对象?

尽可能不允许将对象构造为无效状态。您可以使用Guard ClausesCode Contracts在对象的构造函数中表达这些约束。

public class EmploymentInformation
{
    public EmoloymentInformation(Employer employerInstance)
    {
        if(employerInstance == null)
            throw new ArgumentNullException();
    }

其次,您可以使用Null Object模式,这样您就不必抛出异常。只需为EmptyEmployer创建适当的类并返回它们,如下所示。

        public Company Employer
            {
                get
                {
                    return IsEmployed ? _employer : Employer.Empty; 
// Employer.Empty is static property which return an instance of EmptyEmployer just like string.Empty.


    }

答案 3 :(得分:1)

新答案:

鉴于该对象严格保存有关用户CURRENT员工状态的数据,它仍然是错误的。

正如@Jeff Sternal所说,你不应该强迫开发人员根据特定的顺序分配参数。如果对象需要序列化/反序列化,最终可能会出现很多错误。

相反,您应该提供验证功能。像bool IsValid();之类的东西当调用该方法时,执行业务逻辑验证以确保对象处于可接受的状态。如果没有,你可以简单地返回一个假,抛出一个异常(请不要),或让它发回一个状态代码,说明对象当前无效的原因。

通常,您将数据抛出到对象中,然后在持久性之前验证对象是否良好。以上只是这样做的一种方式。其他人包括一个业务逻辑库,它将逻辑与数据类完全分开(个人而言,我从来不明白为什么要这样做,但很多人都会发誓。)。

答案 4 :(得分:0)

我没有任何经验,但我认为在某处我会考虑代码合约。

看看这些链接:

http://social.msdn.microsoft.com/Forums/en/codecontracts/thread/1ca2d371-4b85-479d-9e00-64c84e372f02

http://msdn.microsoft.com/en-us/devlabs/dd491992.aspx

您可以使用适合您应用的“要求”来装饰您的属性。看起来很酷,它似乎是IDE的一半集成。

答案 5 :(得分:0)

从逻辑角度来看,这看起来是错误的。

该对象名为“EmploymentInformation”,并且具有名为“EmploymentStatus”的属性

这似乎要么允许就业信息处理活跃或定期雇员的情况;或者,允许就业历史。

如果其中任何一个都是真的,那么在我看来,你可以拥有一个职业但是因为任何原因而拥有像“非雇用”这样的就业状况。

毕竟,让我们看看记录最初是在使用EmploymentStatus的地方创建的。然后,状态将更改为“NotEmployed”下次加载对象时,您将丢失数据。

答案 6 :(得分:0)

如果你是严格的,你可能会说失业的人没有职业或雇主,所以一个人的对象不应该有这些财产。这导致了这样的事情。

class Person
{
    public EmploymentStatus EmploymentStatus { get; set; }
}

class EmployedPerson : Person
{
    public string Occupation { get; set; }
    public Company Employer { get; set; }
}

然而在实践中,这种不可原谅的对象模型使用起来会很麻烦,因为在实例化对象之前,您需要知道某个人是否受雇。在就业和失业之间进行转换也很困难,因为您必须创建一个新对象并复制所有内容。

临床区别不值得。我认为这是正确的,事实上更合乎逻辑的是,向失业者询问他们的雇主是什么,并且他们回答“我没有一个人”,而不是首先无法提出问题。

对我来说,这将是一个更灵活的人。

class Person
{
    public Person()
    {
        this.EmploymentStatus = EmploymentStatus.Unemployed;
    }

    public void Hire(Company employer, string occupation)
    {
        this.Occupation = occupation;
        this.Employer = employer;
        this.EmploymentStatus = EmploymentStatus.Employed;
    }

    public void Fire()
    {
        this.Occupation = null;
        this.Employer = null;
        this.EmploymentStatus = EmploymentStatus.Unemployed;
    }

    public EmploymentStatus EmploymentStatus { get; private set; }
    public string Occupation { get; private set; }
    public Company Employer { get; private set; }
}