Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oop 在可扩展类层次结构中实现单一责任原则的技术/模式_Oop_Design Patterns_Inheritance_Single Responsibility Principle - Fatal编程技术网

Oop 在可扩展类层次结构中实现单一责任原则的技术/模式

Oop 在可扩展类层次结构中实现单一责任原则的技术/模式,oop,design-patterns,inheritance,single-responsibility-principle,Oop,Design Patterns,Inheritance,Single Responsibility Principle,例如,单一责任原则规定,Invoice类不应包含打印自身的代码。印刷应分为不同的类别 但假设您在软件的不同层中有一个Invoice类的层次结构: namespace CoreLayer { public class Invoice { public virtual void Print() { ... } } } namespace CustomizedLayer { public class LaborInvoi

例如,单一责任原则规定,
Invoice
类不应包含打印自身的代码。印刷应分为不同的类别

但假设您在软件的不同层中有一个
Invoice
类的层次结构:

namespace CoreLayer {
    public class Invoice {
        public virtual void Print() {
            ...
        }
    }
}

namespace CustomizedLayer {
    public class LaborInvoice : Invoice {
        public override void Print() {
            ...
        }
    }

    public class AccountInvoice : Invoice {
        public override void Print() {
            ...
        }
    }
}
哪些技术或设计模式可用于区分打印响应性

想法:

  • 一个单独的类,包含一个很大的
    if
    语句,用于测试
    Invoice
    的每个子类,并运行适当的打印代码。这似乎是错误的
  • 访客模式。问题在于,访问者接口需要存在于核心层中,并引用定制层中的类。我想能够添加新的子类在自定义层与修改核心层

    • 您真的需要对发票进行子分类吗?除了打印,发票在其他方面是否有所不同?如果否,则不需要有不同的
      发票
      类型,您只需要将不同的
      发票打印机
      类型传递到
      发票
      实例:

      namespace CoreLayer
      {
          public class IInvoicePrinter
          {
              void Print(Invoice invoice);
          }
      
          public class Invoice
          {
          }
      }
      
      namespace CustomizedLayer
      {
          public class LaborInvoicePrinter : IInvoicePrinter 
          {
              public void Print(Invoice invoice) 
              {
                  ...
              }
          }
      
          public class AccountInvoicePrinter : IInvoicePrinter 
          {
              public void Print(Invoice invoice) 
              {
                  ...
              }
          }
      }
      

      您应该有某种IoC为您提供适当的
      发票打印机
      实例。

      我认为下面的解决方案对C#很有用,它没有外部
      ,如果我知道,不建议使用
      访问者
      模式

      public class InvoicePrinterManager
      {
           public void Print(AccountInvoice invoice)
           {
               AccountInvoicePrinter p1 = new AccountInvoicePrinter(invoice);
               p1.print();
           }
      
           public void Print(LaborInvoice invoice)
           {
               LaborInvoicePrinter p1 = new LaborInvoicePrinter(invoice);
               p1.print();
           }
      }
      
      public class InvoicePrinter<T> where T : Invoice, new()
      {
          T instance;
      
          public InvoicePrinter(T invoice)
          {
              if (invoice != null)
              {
                  this.instance = invoice;
              }
              else
                  instance = new T();
          }
      
          public virtual void Print()
          {
              /// Arrange objects as you want and print them.
          }
      }
      
      public class AccountInvoicePrinter : InvoicePrinter<AccountInvoice>
      {
          public AccountInvoicePrinter(AccountInvoice invoice)
              : base(invoice)
          { 
          }
      
          public override void Print()
          {
             /// todo
          }
      }
      
      public class LaborInvoicePrinter : InvoicePrinter<LaborInvoice>
      {
          public LaborInvoicePrinter(LaborInvoice invoice)
              : base(invoice)
          { 
          }
          public override void Print()
          {
              /// todo: use instance
          }
      }
      
      public class Test
      {
          public void TestPrint()
          {
              LaborInvoice li = new LaborInvoice();
              InvoicePrintManager printerManager = new InvoicePrintManager();
              printerManager.Print(li);
          }
      }
      
      公共类InvoicePrinterManager
      {
      公共作废打印(会计发票)
      {
      AccountInvoicePrinter p1=新的AccountInvoicePrinter(发票);
      p1.print();
      }
      公共作废打印(人工发票)
      {
      LaborInvoicePrinter p1=新的LaborInvoicePrinter(发票);
      p1.print();
      }
      }
      公共类发票打印机,其中T:Invoice,new()
      {
      T例;
      公共发票打印机(T发票)
      {
      如果(发票!=null)
      {
      this.instance=发票;
      }
      其他的
      实例=新的T();
      }
      公共虚拟作废打印()
      {
      ///根据需要排列对象并打印它们。
      }
      }
      公共类AccountInvoicePrinter:InvoicePrinter
      {
      公共帐户发票打印机(帐户发票)
      :基数(发票)
      { 
      }
      公共覆盖无效打印()
      {
      ///待办事项
      }
      }
      公共类LaborInvoicePrinter:InvoicePrinter
      {
      公共人工发票打印机(人工发票)
      :基数(发票)
      { 
      }
      公共覆盖无效打印()
      {
      ///todo:使用实例
      }
      }
      公开课考试
      {
      公共void TestPrint()
      {
      LaborInvoice li=新的LaborInvoice();
      InvoicePrintManager printerManager=新InvoicePrintManager();
      printerManager.Print(li);
      }
      }
      
      < /代码> 您可能想考虑.< /p>我不确定这有助于消除检查发票的每个子类的if语句。如果我有一个要打印的发票对象,如何获得适当的InvoicePrinter来打印它?当您知道呼叫者在哪里时,不需要额外的If,但如果您不知道呼叫者,是的,你们应该有一个经理,我不知道如何防止转换和反思。我想了想,但直到我找到任何好主意now@JoeDaley,我刚刚更新了我的答案,有一些额外的东西你可以移除。但我认为应该是一个更好的方式。有趣的阅读!该解决方案在C++中使用多重继承和动态映射。我碰巧正在使用C#,但我认为我仍然可以通过将抽象的访问者类更改为接口来使用它。