首页 > 解决方案 > 使派生类能够仅实现选定数量的基类属性

问题描述

首先,我想描述一下我要解决的问题:

我想制作一个程序来处理法律民事案件。在每个法律案例中,都有一个List<IDocument> LegalDocuments包含该法律案例中可能存在的任何和所有文档的对象。每个文档都派生自基本Document类并实现IDocument接口。可能的文档类型的数量是开放的,可以扩展到超过 100 种。在文档实现的基类中也有很少的公共属性,这是类:

public abstract class Document
{
    //some general properties that all documents implement

    
    //The expiration date of a document
    public DateTime ExpirationDate { get; set; }
    // The series of a document
    public string DocSeries { get; set; }
    //The serial number of a document
    public int DocNumber { get; set; }
    //the amount of money associated with the document
    public decimal MoneyAmount { get; set; }
    // signer of the document The exemplar of LegalSubject is presented below.
    public LegalSubject Signer;
}

public class LegalSubject 
{
 //LegalSubject implementation
}

问题是:并非所有文档都具有所有呈现的属性。例子:

//passport: Has: ExpirationDate, DocSeries, DocNumber. 
//Doesn't have: MoneyAmount, Signer
public class Passport : Document, ILegalDocument { }

//Payment Order: Has: DocNumber, MoneyAmount
// Doesn't have: The rest
public class PaymentOrder : Document, ILegalDocument { }

//Power of Attorney: Has: ExpirationDate, Signer
//Doesn't have: The rest
public class PowerOfAttorney : Document, ILegalDocument { }

// The common interface for the documents to fit into the list.
public interface ILegalDocument { }

这个想法是外部代码应该测试某个文档是否具有某个属性并根据结果启用/禁用相应的 UserForm 控件(例如)。

我能想到的唯一明智的方法是策略模式,其中我将每个属性的实现移动到一个单独的类并通过接口实现它们,这是代码:

using System;
using System.Collections.Generic;
using System.Text;

namespace ExampleLegalDocuments
{


    public class Passport : Document, ILegalDocument 
    { 
        public Passport()
        {
            //the constructor implements only the properties that Passports have.
            ExpirationDate = new ExpirationDateEnabled();
            Docseries = new DocSeriesEnabled();
            DocNumber = new DocNumberEnabled();
        }
    }
    //public class PaymentOrder : Document, ILegalDocument { }
    //public class PowerOfAttorney : Document, ILegalDocument { }

    //an interface for all derived types of documents 
    public interface ILegalDocument {
        //The expiration date of a document
        public IExpirationDate ExpirationDate { get; set; }
        // serires of a document
        public IDocSeries Docseries { get; set; }
        // serial number of a document
        public IDocNumber DocNumber { get; set; }
        // a sum of money, associaned with the document
        public IMoneyAmount MoneyAmount { get; set; }
        // an exemplar of LegalSubject class (shown below) who is a signer of the document
        public ISigner Signer { get; set; }
    }
    
    public abstract class Document
    {
        //some general properties that all documents implement


        //The expiration date of a document
        public IExpirationDate ExpirationDate { get; set; }
        // serires of a document
        public IDocSeries Docseries { get; set; }
        // serial number of a document
        public IDocNumber DocNumber { get; set; }
        // a sum of money, associaned with the document
        public IMoneyAmount MoneyAmount { get; set; }
        // an exemplar of LegalSubject class (shown below) who is a signer of the document
        public ISigner Signer { get; set; }

    }
    public class LegalSubject { }

    //interfaces for the properties;
    public interface IExpirationDate
    {
        public DateTime value { get; set; }
    }
    public interface IDocSeries 
    { 
        public string value { get; set; }
    }
    public interface IDocNumber
    {
        public string value { get; set; }
    }

    public interface IMoneyAmount
    {
        public decimal value { get; set; }
    }
    public interface ISigner
    {
        public LegalSubject value { get; set; }
    }

    //classes implementing the values through the interfaces shown above above
    public class ExpirationDateEnabled : IExpirationDate
    {
        public DateTime value { get; set; }
    }

    public class DocSeriesEnabled : IDocSeries
    {
        public string value { get; set; }
    }

    public class DocNumberEnabled : IDocNumber
    {
        public string value { get; set; }
    }

    public class MoneyAmountEnabled : IMoneyAmount
    {
        public decimal value { get; set; }
    }

    public class SignerEnabled : ISigner 
    {
        public LegalSubject value { get; set; }
    }
}

执行:

using System;
using System.Collections.Generic;

namespace ExampleLegalDocuments
{
    class Program
    {
        static void Main(string[] args)
        {
            Passport testPassport = new Passport();

            if (testPassport.DocNumber is IDocNumber) { Console.WriteLine("property enabled"); } 
            else { Console.WriteLine("property not enabled"); }; //property enabled
            if (testPassport.Signer is ISigner) { Console.WriteLine("property enabled"); } 
            else { Console.WriteLine("property not enabled"); }; //property not enabled

            testPassport.DocNumber.value = "123";

            List<ILegalDocument> LegalDocuments= new List<ILegalDocument>();
            DocList.Add (testPassport);

            Console.WriteLine("Document number is {0}", LegalDocuments[0].DocNumber.value); //Document number is 123

        }
    }
}

testPassport.Documenber.value似乎对我有用,尽管我不喜欢更深入地访问一个值,即testPassport.value我的方法是否正确?

标签: c#oopstrategy-pattern

解决方案


推荐阅读