An example with the addition of the interface:

class Playback { private Media current; public void play(Media media) { current.stop(); current = media; current.play(); } public void next() { Media media // ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΏΠΎ ΠΊΠ°ΠΊΠΎΠΌΡƒ Π»ΠΈΠ±ΠΎ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΡƒ play(media); } public void prev() { Media media // ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ ΠΏΠΎ ΠΊΠ°ΠΊΠΎΠΌΡƒ Π»ΠΈΠ±ΠΎ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΡƒ play(media); } } 

Example with the addition of classes of operations:

 class Playback { private Media current; public Media current() { return current; } public void play(Media media) { current.stop(); current = media; current.play(); } } abstract class PlayOperation { private Playback playback; public void execute() { Media media = provide(); playback.play(media); } protected abstract Media provide(); } class NextOperation extends PlayOperation { public Media provide() { Media media // ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ ΠΏΠΎ ΠΊΠ°ΠΊΠΎΠΌΡƒ Π»ΠΈΠ±ΠΎ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΡƒ return media; } } class PrevOperation extends PlayOperation { public Media provide() { Media media // ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ ΠΏΠΎ ΠΊΠ°ΠΊΠΎΠΌΡƒ Π»ΠΈΠ±ΠΎ Π°Π»Π³ΠΎΡ€ΠΈΡ‚ΠΌΡƒ return media; } } class RandomOperation extends PlayOperation { private Random random; public Media provide() { Media media // ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Ρ€Π°Π½Π΄ΠΎΠΌΠ½ΠΎΠΉ return media; } } 

An example with new classes looks more attractive, but is it worth it?

  • one
    Well, in my opinion, it all depends on a wider architectural context. If you need entities that embody operations in the context of a higher-level architectural solution (say, you need to be tied to the GUI), then yes, this may make sense. And if there is no such context, then I would not write templates for the sake of the templates themselves - I respect Ockham. - m. vokhm

1 answer 1

Example with adding operation classes

What you described in the example is almost the Visitor design pattern. NextOperation , PrevOperation , RandomOperation - Playback class visitors. In this case, this template is hardly justified, since it is intended to add the behavior of the class hierarchy, and it really plays on OCP when working with a hierarchy (because the need to add behavior to the tree of heirs by adding a method to the base class will break OCP). You have one Playback class - OCP will not be broken in the first case - Playback open for expansion by inheritance (if you change private to protected , of course), and is closed for changing (this means that you do not need to rewrite it to refine behavior in successors).

It is impossible not to see the minus of the second approach - you seriously complicate the system by spreading simple logic into many classes (this is Anti-SRP ). Therefore, I would advise you to leave the first option, at least when the system is simple - you cannot complicate it so much, YAGNI is against .

But if the Playback becomes the base class of the hierarchy, the use of visitors will already be justified, and the visit(PlayOperation operation) method should be added, and the possibility of visiting the Playback does not mean that the next() method, for example, must be moved to the visiting class: visitors are better to make additional operations, and the main - to leave inside the class.

  • It should also be noted that OCP is a very controversial principle for projects that are not a library / framework. For the rest, the dependencies on the logic that is changed in the abstract class are traced quickly with the help of IDE (with constant dogma - programmers' access to all tools, of course). But on the other hand, if OCP is not perceived directly - it says β€œmake objects flexible”, which must always be taken into account. - Goncharov Alexander
  • "no need to rewrite" and "closed for change" are still different things. - etki
  • @Etki what about your OCP? Add the answer - the one who will look for information about OCP will come across and it will be interesting :) If you interpret closeness - as something related to inheritance, then this is already LSP, I think. The closed nature of OCP is, it seems to me, the flexibility of a component β€” which allows, without changing its code, to reuse it in a wide variety of variations. - Goncharov Alexander