Yes, multiple ways, including
implemented ways.
For the examples I am going to use the typical "HTTP to example.com" case.
Some OSI-focused stacks provided high level abstraction that gave you a socket already set for listening or connected to another service, based on combination of "host name", "service name", and "service type".
You'd use something like
connect("example.com", "http", SVC_STREAM_GRACEFUL_CLOSE) // using OSI-like name for the kind of service TCP provides
and as far as application is concerned, it does not need to know if it's ipv4, ipv6, X.25, or a direct serial connection (OSI concept of separating "service" from "protocol" is really a great idea that got lost)
Similar approach was done in Plan 9 (and thus everyone who uses Go is going to see something similar) with the dial API:
dial("example.com!http",0,0,0)
As part of IPv6 effort an attempt at providing something similar with BSD Sockets was made, namely getaddrinfo which gives back information to be fed to socket/bind/connect calls - but for a long time people still learnt from old material which had them manually fill in socket parameters without GAI so adoption was slowed down.