簡體   English   中英

C ++:在不違反SRP的情況下將方法添加到多態類層次結構中?

[英]C++: Adding methods to a polymorphic class hierarchy without violating SRP?

我有一個經常遇到的設計問題。

為了便於說明,我們假設我有一個多態類層次結構

class A { public: virtual ~A() {} ... };
class B: public A { ... };
class C: public B { ... };
class D: public A { ... };
...

我希望能夠以多態方式打印這些類的實例,即每個類都有自己的打印方式。 實現這一目標的顯而易見的方法是添加

virtual void print(OutputStream &os) = 0;

進入基類並在每個子類中重寫此方法。 但是,如果類的原始職責與打印無關,則會給他們增加另一項責任,從而違反了SRP

我的問題是:在不違反SRP的情況下,實現理想行為的正確方法是什么?

這篇文章中 ,提出了一種基於訪問者設計模式的解決方案。 但是,我需要創建一個必須知道A每個子類的類。 我希望能夠添加和刪除子類,而無需始終修改訪問者。

除了上述兩種方式之外,還有其他一些SRP保留方式嗎?

有一個非循環訪問者模式,無需了解每個子類。 它依賴於dynamic_cast ,但可能就是你所需要的。

班級打印本身沒有錯。 它不違反SRP,因為打印不構成責任。

請記住,責任被定義為改變的理由。 您不會更改類,因為您對打印的要求會發生變化。 該類應該只向負責打印的實體發送名稱 - 值對,稱為格式化程序 發送名稱 - 值對的過程永遠不會自行更改。 其中的任何更改僅由與打印無關的其他更改提示(當您添加字段時,還會將其表示添加到打印過程中)。

格式化程序應該對它打印的類一無所知,而只是根據一些要求提供名稱 - 值對。 當打印要求發生變化時,格式化程序會更改。 因此,打印將是格式化程序的唯一責任。

為了做到這一點,你需要找一些雙重調度解決方案的訪問者。 雙重調度方法更輕量級,所以如下所示:

在一個:

class Processor
{
public:
  virtual void Process(const A &a)const {}
  virtual void Process(const B &b)const {}
  virtual void Process(const C &c)const {}
  virtual void Process(const D &d)const {}
  virtual void Process(const E &e)const {}
};

在一個:

class A
{
public:
  virtual void Process(const Processor &processor) 
  {
    processor.Process(*this);
  }
};

然后,在每個派生類中重寫具有相同定義的Process

virtual void Process(const Processor &processor) 
{
  processor.Process(*this);
}

這將確保調用Process中的正確重載。

現在,創建一個流處理器:

class StreamProcessor : public Processor
{
private:
 OutputStream &m_OS;

public:
  StreamProcessor(OutputStream &os) : m_OS(os)
  {
  }

  virtual void Processor(const A &a)const
  {
   m_os << "got a A";
  }

  virtual void Processor(const B &b)const
  {
   m_os << "got a B";
  }

  virtual void Processor(const C &c)const
  {
   m_os << "got a C";
  }

  // etc
};

然后:

 OutputStream &operator<<(OutputStream &os, A &a)
 {
   PrintProcessor(os);
   a.Process(PrintProcessor);
   return os;
 }

您可以提供打印責任的界面,並在類層次結構下保持共同的職責。 例:

class Printer { public: virtual void print(OutputStream &os) = 0; }
class A { public: virtual ~A() {} ... };
class B: public A, public Printer { ... }; // this needs print function, use interface.
class C: public B { ... };
class D: public A { ... };

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM