假设我有一个使用特殊网络套接字的应用程序,该应用程序通过XML格式的套接字传输数据,称为 XMLSocket
。
XMLSocket
继承 basesocket
,并满足Liskov替代原则。我们可以互换它们。
我有一个客户端应用程序,该应用程序使用 xmlsocket
:
class Client:
def start(sock: BaseSocket):
sock.connect(ip, port)
sock.send(some_request)
some_response = sock.recv()
现在,我们可以通过 xmlsocket
或 basesocket
baseSocket to client.start(),此代码有效。
我们甚至可以添加更多 basesocket
的推导,例如 jsonsocket
,只要整体流,功能签名和返回类型相同,它仍然可以与层次结构中的任何插座类。然而,这违反了依赖性反转原则。
现在,让我们创建一个接口 isocket
:
class ISocket(ABC):
def connect(ip, port):
pass
def send(request):
pass
def recv() -> Response:
pass
make client.start()
取决于我们的接口,因此满足依赖关系反转原则:
class Client:
def start(sock: ISocket):
sock.connect(ip, port)
sock.send(some_request)
some_response = sock.recv()
好吧,似乎我们已经完成了与基类同样的事情。只要它的行为就像插座,我们可以通过任何插座的变化。
,为什么它必须取决于抽象,而不是基类?
Let's say I have an application which uses a special network socket, which transmits data over a socket in XML format called XMLSocket
.
XMLSocket
inherits BaseSocket
, and satisfies the Liskov Substitution Principle. We can interchange them.
And I have a client application which uses XMLSocket
:
class Client:
def start(sock: BaseSocket):
sock.connect(ip, port)
sock.send(some_request)
some_response = sock.recv()
Now, we can pass XMLSocket
or BaseSocket
into Client.start()
, and this code works.
We could even add on more derivations of BaseSocket
such as JSONSocket
, and as long as the overall flow, function signatures, and return types are the same, it would still work with any of our socket classes in the hierarchy. Yet, this violates the dependency inversion principle.
Now let's create an interface ISocket
:
class ISocket(ABC):
def connect(ip, port):
pass
def send(request):
pass
def recv() -> Response:
pass
And make Client.start()
depend on our interface instead, therefore satisfying the dependency inversion principle:
class Client:
def start(sock: ISocket):
sock.connect(ip, port)
sock.send(some_request)
some_response = sock.recv()
Well, it seems like we've accomplished the same exact thing as the base class did. We can pass in any variation of a socket we can dream of, as long as it behaves like a socket.
So, why must it depend on an abstraction, instead of a base class?
发布评论
评论(1)
最好使用抽象类或界面作为:
不要从具体类中得出。或者,正如斯科特·迈耶斯(Scott Meyers)在更有效的C ++的第33项中所说的那样,[8]“ “(诚然,它可以在实践中发生 - 当然是由其他人撰写的代码,而不是您!但是,如果可以的话,可以更好地进行重构和修复设计。
不可能从抽象类创建实例。因此,添加抽象方法更容易。通过使用
摘要
关键字或接口,您可以告诉其他开发人员和编译器从中继承来创建一个具体的实现。It is better to use abstract class or interface as:
Don't derive from concrete classes. Or, as Scott Meyers puts it in Item 33 of More Effective C++,[8] "Make non-leaf classes abstract." (Admittedly, it can happen in practice - in code written by someone else, of course, not by you! - and in this one case you may have to have a public virtual destructor just to accommodate what's already a poor design. Better to refactor and fix the design, though, if you can.)
It is not possible to create instance from abstract class. So it makes easier to add abstract methods. And by using
abstract
keyword or interface you tell to other developers and compiler to inherit from it to create a concrete useful implementation.