Are design patterns really language weaknesses?

2019-01-21 03:05发布

问题:

Should today's patterns be seen as defects or missing features in Java and C++?

  • Subroutine was a design pattern for machine language in the 50s and 60s.
  • Object-Oriented Class was a design pattern for C in the 70s.
  • Visitors, Abstract Factories, Decorators, and Façades are design patterns for Java and C++ today.

    What will tomorrow's languages look like? What patterns will they have?

回答1:

Some canonized design patterns -- Adapter, Factory, Command, Visitor, etc -- are approximations of features which are baked into other languages. Off the top of my head:

  • Event-handlers in C# are baked-in versions of the observer pattern. Think about how you'd wire up events in C# if you had to roll your own observer each time.

  • Visitor pattern is a verbose approximation of multimethods, message forwarding, or a really weak form of pattern matching.

  • Command pattern wraps up a particular behavior so you can pass the object between methods, which more or less approximates first-class functions.

  • Strategy pattern allows you to dynamically insert a behavior into an object, so that at any time you can modify the object by swapping out one behavior with another. In the functional programming world, we call this function composition.

  • Abstract factory pattern accepts an argument and returns a factory as a result. In general, you can think of factories as basically wrappers around a function (more specifically, wrappers around a constructor). So, you pass arguments to a function and get a function as a result, making this pattern pretty analogous to currying.

  • Decorator pattern allows you to attach or remove behaviors to an object at runtime. In JavaScript, you can add or remove functions without explicitly implementing the decorator pattern thanks to the "prototype" OO model.

So, we have a bunch of design patterns which emulate features intrinsic to other languages. Feature envy doesn't necessarily indicate a weakness in the language -- it's the boilerplate code that you need to write over and over and over which indicates the language weakness.



回答2:

I wouldn't call them defects.

Higher order languages deal with concepts at a higher level than lower order languages. Think of it in construction terms.

You could build a building at the refinery level, milling lumber, smelting steel, and put together a building that way.

You could purchase boards and steel girders, and construct them into a building.

You could purchase pre-fabricated walls and trusses and construct them into a building.

You could purchase a building and just start with the interior.

Is constructing a building with boards and girders missing the prefabricated wall feature, or defective in some way?



回答3:

Every single thing that you do three or more times in software designs forms a pattern.

Every repetition. Every repetition. Every repetition.

Some get canonized with cool names. These become Design Patterns. Conscious repetition.

Some are just "best practices" or "this has worked for me." These are design patterns without the clarity.

Some are just "things you usually do." These are design patterns without any conscious recognition that you're repeating yourself.

Design patterns have nothing to do with language weakness or incompleteness. They have everything to do with good ideas, consciously reused.

Today's design patterns are not the royal road to tomorrow's languages. The language paradigm does not advance through a series of "bug fixes to previous languages". If it did, we'd never have created Visual Basic.

And design patterns are a far larger and broader intellectual tool than a simplistic programming language feature set.



回答4:

No, they are not missing features or defects of the languages. But the languages should provide a means for writing the code for a useful pattern easier rather than difficult. That's where the features that are provided by the language can either be a boon or a hindrance.



回答5:

I think Ewan brings up a fascinating point. Take his "subroutine" example. In early programming languages, the idea of passing parameters to a subroutine and returning a result was something that you had to explicitly code. In modern languages, it's built in. Or to take another example: If/then/else is built into most if not all modern languages. But back in my assembler days, I had to write code to accomplish that. Not a lot, of course, but still, you had to actually write the jump or goto statement to go around the else block. And the fact that you had to write these things yourself meant that different programmers would do it in slightly different ways, and there was the endless temptation to be clever and do it a little differently in this program to make it more efficient or gain some other supposed advantage.

The most recent example that comes to mind is iterators. You have to hand-write them in C++ and early versions of Java, but they're built in to Java 5. This is arguably syntactic sugar, you're just as well to simply create iterator functions. Personally I think it's a nice feature. Does it radically improve my productivity? No.

Is there something that we are doing all the time that should logically be built into the language to standardize and simplify it? A fascinating question. I don't suppose that anyone will seriously claim that even their favorite language is perfect and absolutely no improvement is possible. But what will the direction of the next language be?

Surely some features that have been added to languages are useless extra baggage. In my humble opinion, Java enum's do way more than is necessary, they add a bunch of baggage for no good reason. I'm sure others will disagree and say that they find them incredibly useful.

I don't have a conclusion. I just agree that it's a fascinating question.



回答6:

I've read somewhere something like "the more patterns you have, the less powerful your language is" and I find this definition very nice.

The reason is IMO clear: if you see a repeated pattern (or you have to use it) it means that it's a sort of copy'n paste at a logical level. Of course it's not as bad as copy'n paste of statements, but it's still redundancy. I'm still repeating myself again and again.

The more the language is expressive and the more you should be able to capture and factor this redundancy out by transforming it in reuse instead of reimplementation, and the reuse will be easier to read and understand in the source code.

Every time you find yourself doing the same thing once again (including e.g. "ok... let's implement an abstract factory here") it means that's something that should have been expressed at an higher level.

Of course sometimes you can try to capture the essence of something, but the reuse may be uglier to read than the reimplementation (I'm thinking for example to some parts of C++ "high-level" stuff in <algorithm>). This is IMO a clear sign that the language is not expressive enough.



回答7:

I think some design patterns do represent language weaknesses and new languages incorporate existing patterns into first class citizens. An example of a new language taking existing design patterns in other languages (dependency injection, immutability, etc.) and incorporating them as first class language level features is NOOP from Google.



回答8:

I am wondering how much you can cram into a language before it gets too "large."

I like the language I am working with to be small enough to hold in my head all at once. Patterns such as DI have to do with structural concerns; should that be a part of the language?

How much hand-holding in the language does a developer really need?

In the case of Code Contracts (requires, ensures), it is nice when that is a first-class part of the language, but it is not required. It can still be part of a library.



回答9:

Frameworks that facilitate the use of certain patterns in languages do exist, so they're more of a choice rather than a must. There are patterns that for a certain project, you might just not need, so incorporating a lot of them as primary language features would only impose restrictions rather than facilitate productive work.



回答10:

each language is an arbitrary set of design patterns with syntax as the notation for the chosen patterns. for the unchosen patterns, you have to meddle within the constraints of the syntax to express them. most of the languages does not allow its syntax to change much to assimilate higher level patterns.

a language that can do that limitlessly would be one without a rigid syntax. (or in another way, one that allows to seamlessly assimilate any high level pattern). see metalinguistic abstraction

the one that comes to my mind is scheme/lisp.



回答11:

Design patterns are not weakness in languages. They provide design solutions to recurring problems.

Since many things have been evolving over time, I think Enterprise Integration Patterns are going to be popular.

If different enterprise application have to communicate, these patterns provides best solutions.

  1. Integration Styles document different ways applications can be integrated, providing a historical account of integration technologies. All subsequent patterns follow the Messaging style.
  2. Channel Patterns describe how messages are transported across a Message Channel. These patterns are implemented by most commercial and open source messaging systems.
  3. Message Construction Patterns describe the intent, form and content of the messages that travel across the messaging system. The base pattern for this section is the Message pattern.
  4. Routing Patterns discuss how messages are routed from a sender to the correct receiver. Message routing patterns consume a message from one channel and republish it message, usually without modification, to another channel based on a set of conditions. The patterns presented in this section are specializations of the Message Router pattern.
  5. Transformation Patterns change the content of a message, for example to accommodate different data formats used by the sending and the receiving system. Data may have to be added, taken away or existing data may have to be rearranged. The base pattern for this section is the Message Translator.
  6. Endpoint Patterns describe how messaging system clients produce or consume messages.
  7. System Management Patterns describe the tools to keep a complex message-based system running, including dealing with error conditions, performance bottlenecks and changes in the participating systems.