LINUX.ORG.RU

А существует ли стратегия?:)

 , ,


0

1

Вчера я начал разбираться, и будто бы, начал что-то понимать, (спасибо всем откликнувшимся, отдельное спасибо TDrive), но сегодня решил разобрать следующий пример, и снова впал в какой то ступор.

взято отсюда: http://habrahabr.ru/post/191480/

// Greeter - класс объектов, которые могут приветствовать людей.
// Он может выучить различные способы приветствия через стратегии
var Greeter = function(strategy) {
    this.strategy = strategy;
};
 
// Greeter содержит функцию greet,
// которая будет использоваться для приветствия людей
// через стратегии, переданные в конструктор
Greeter.prototype.greet = function() {
    return this.strategy();
};

// Так как функция инкапсулирует алгоритм,
// она отличный кандидат на роль стратегии

// Немного стратегий:
var politeGreetingStrategy = function() {
    console.log("Hello.");
};
 
var friendlyGreetingStrategy = function() {
    console.log("Hey!");
};
 
var boredGreetingStrategy = function() {
    console.log("sup.");
};
 
// Давайте используем их!
var politeGreeter = new Greeter(politeGreetingStrategy);
var friendlyGreeter = new Greeter(friendlyGreetingStrategy);
var boredGreeter = new Greeter(boredGreetingStrategy);
 

Код, воистину элементарен.

Все это можно переписать вот так

Greeter=function(strategy){this.strategy=strategy}
Greeter.prototype.greet=function(){this.strategy()}

politeGreeter=new Greeter(function(){console.log("Hello")})
friendlyGreeter=new Greeter(function(){console.log("Hey")})
boredGreeter=new Greeter(function(){console.log("sup")})
То есть, де факто, автор просто создает экземпляры Greeter, и сеттит им поведение. Иными словами, делает то, что мы и так всегда делаем, когда пишем ООП-код. Больше тут ничего нет.

Мало того, для выражения данной абстракции, даж этот код избыточен. Я его привел просто для того, чтобы была полная семантическая эквивалентность. А по хорошему, это стоило бы записать вот так

Greeter=function(greeting){this.greeting=greeting}
Greeter.prototype.greet=function(){console.log(this.greeting)}

politeGreeter=new Greeter("Hello")
friendlyGreeter=new Greeter("Hey!")
boredGreeter=new Greeter("sup")
Ибо нефиг размазывать поведение по объектам, там где его можно обобщить.

А может нет никакой «стратегии», а? Может это фантом коллективного-бессознательного?

Ответ на: комментарий от loyd
let a = { foo() { return "a" } };
let foo = a.foo;
a.foo = function() { retrun foo.call(this) + "b"; }

это круто если нужно по мелочи поменять вывод одной функции, а когда таких функций больше 1 задумываешься об инкапсуляции.

Применимо. Но когда нужен, например, прокси, гораздо быстрее сконструировать ограниченный объект на лету, обладающим нужными свойствами и методами, без полноценного наследования.

Это все частные случаи, динамический яп дает дополнительные возможности но говорить о потере смысла классических паттернов явно перебор.

TDrive ★★★★★
()
Ответ на: комментарий от loyd

Это не всегда так. Большинство реализаций синглтона (напр., крестовые) предполагают получение экземпляра через какой-нибудь getInstance().

Это скорее исключение, в тойже книге от банды четырех про этот момент отдельно написано, там ряд проблем с реализацией этого паттерна в C++ по этом такой вот костылик.

TDrive ★★★★★
()
Ответ на: комментарий от javaQest

Грубо говоря паттерн это и есть определенная реализация, такая реализация которую с большей вероятностью не придется рефакторить в будущем и которую будет легко поддерживать, адаптировать под новые требования. Тот же синглтон можно заменить на глобальную переменную которая инициализируется объектом но ее будет неудобно поддерживать. паттерн декоратор можно заменить наследованием, но это будет сложнее поддерживать, стратегию опять же можно заменить наследованием и полотном ифов, вместо очередной стратегии создавать подклас контекста с переопределенной функцией, но это говно будет сложно поддерживать и рано или поздно придется отрефакторить, + логику нельзя использовать в разных контекстах, куча минусов от которых спасает применение паттерна.

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

Я имею в виду что класс может стать синглтоном, может перестать быть синглтоном и при этом интерфейс общения с этим классом для остальной программы не поменяется.

Не вижу препятствий

singletone := Object clone do(
 set := method(if(self hasLocalSlot("clone"), self removeSlot("clone"), self clone = singletone))
)

writeln(singletone clone == singletone)
singletone set
writeln(singletone clone == singletone)
singletone set
writeln(singletone clone == singletone)
singletone set
writeln(singletone clone == singletone)


false
true
false
true

javaQest
() автор топика
Ответ на: комментарий от TDrive

Нет, в отличае от {..} у синглтона есть инициализация выполняемая при первом использовании

Не совсем понятно, что тут имеется в виду под {..}, но если имеется в виду литерал объекта, то конструкция {..} — это и есть инициализация экземпляра Object, это сахар для new Object(..), другое дело, что к синглтонам это не имеет никакого отношения. о чем вы тут говорите, не совсем понятно.

javaQest
() автор топика
Ответ на: комментарий от loyd

Но если у тебя синглтон перестанет быть синглтоном, никто не запрещает инстанцировать класс через getInstance, поэтому можно ограничиться изменениями реализации класса, не затрагивая остальной код. Почему приверженцы C++ и Java стремятся при этом отрефакторить весь код, я не знаю, наверное так принято.

winlook38 ★★
()
Ответ на: комментарий от javaQest

Имелось в виду, что синглтон в частном случае эквивалентен модулю, а значит и {..}. Ну а если говорить в контексте Proxy из ES6, то проксированный {..} может быть синглтоном в широком смысле.

loyd
()
Ответ на: комментарий от loyd

А, ну это да, я почему-то решил, что речь о том, что класс был синглтоном, а потом вдруг стал обычным, мультитоном или пулом.

winlook38 ★★
()
Ответ на: комментарий от TDrive

Это все частные случаи, динамический яп дает дополнительные возможности но говорить о потере смысла классических паттернов явно перебор.

ну, вот взять тот же синглтон, к примеру. Зачем он может понадобиться в JS? пиши singleton={}, и обращайся к этой переменной как к синглтону, она полностью заменит его.

Собственно, он нужен в языках, где невозможно без костылей создать глобальную точку доступа.

А вообще, синглтоном, по сути, является любой примитив. Например null — синглтон.

javaQest
() автор топика
Ответ на: комментарий от javaQest

Не совсем понятно, что тут имеется в виду под {..}, но если имеется в виду литерал объекта, то конструкция {..} — это и есть инициализация экземпляра Object, это сахар для new Object(..),

Она инициализируется при определении, а не при первом вызове, что мягко говоря неудобно если инициализация подразумевает какие либо параметры.

другое дело, что к синглтонам это не имеет никакого отношения. о чем вы тут говорите, не совсем понятно.

это относится к синглтонам так же как и глобальная переменная.

TDrive ★★★★★
()
Ответ на: комментарий от javaQest

ну, вот взять тот же синглтон, к примеру. Зачем он может понадобиться в JS? пиши singleton={}, и обращайся к этой переменной как к синглтону, она полностью заменит его.

Только что написал про инициализацию.

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

Она инициализируется при определении, а не при первом вызове, что мягко говоря неудобно

LOL, «определение» — это и есть вызов + связывание a={}

если инициализация подразумевает какие либо параметры.

Если инициализация требует параметров, создается, например, конструктор, который инициализирует экземпляр с параметрами.

javaQest
() автор топика
Ответ на: комментарий от javaQest

Если инициализация требует параметров, создается, например, конструктор, который инициализирует экземпляр с параметрами.

+ куча проверок на невозможность использовать неинициализированный объект.

TDrive ★★★★★
()
Последнее исправление: TDrive (всего исправлений: 1)
Ответ на: комментарий от TDrive

и глобальная переменная.

и чо вы все время привязываетесь к какой-то глобальности. Никакой разницы, глобальная она или не глобальная, вообще нет. Она должна быть глобально доступна, а не «глобальная».

javaQest
() автор топика
Ответ на: комментарий от TDrive

+ куча проверок на невозможность использовать неинициализированный объект.

О чем ты говоришь? Объект создается, инициализируется и связывается с какой-либо переменной, в дальнейшем, он доступен по этому адресу. Если переменной с ним связанной не существует, значит и обратится ты к нему не можешь, какие тут проверки?

javaQest
() автор топика
Ответ на: комментарий от javaQest

А вообще, синглтоном, по сути, является любой примитив. Например null — синглтон.

В общем то он может и не являться синглтоном, что конечно глупо но может быть.
Если у экземпляра класса только одно состояние то его логично сделать синглтоном так как все экземпляры в любом случае будут идентичны. И даже если 2-3 состояния все равно стоит подумать о синглтонах, так например в руби true и false это 2 синглтона, а не разные состояния какого нибудь обыекта класса Boolean.

TDrive ★★★★★
()
Ответ на: комментарий от javaQest

О чем ты говоришь? Объект создается, инициализируется и связывается с какой-либо переменной, в дальнейшем, он доступен по этому адресу. Если переменной с ним связанной не существует, значит и обратится ты к нему не можешь, какие тут проверки?

Представь что твой объект занимает овер дохрена строчек, а данные для его инициализации появляются где нибудь в середине программы, ты весь этот {..} запихаешь в середину программы там где он сможет инициализироваться? Нет потому что другие программисты сломают тебе руки за такое. Значит ты сделаешь этому объекту какой нибудь метод initialize который будешь дергать в момент появления данных для инициализации, но тебе придется написать еще овер дохрена строчек проверок что бы исключить возможность использования этого объекта до инициализации, либо использовать синглтон который сам по себе подразумевает возможность инициализации в любой момент + стандартную проверку во время инициализации так как без вызова new им в принципе нельзя будет воспользоваться

TDrive ★★★★★
()
Последнее исправление: TDrive (всего исправлений: 1)
Ответ на: комментарий от TDrive

Какие например?

Delegation, Functional, Interface, Property Container, Event Channel, Abstract factory, Factory method, Multiton, Singleton, Prototype, Adapter, Bridge, Composite, Decorator, Proxy, Command, Iterator, Mediator, Memento, Null object (?.), Servant, Strategy, Template method, Visitor.

anonymous
()
Ответ на: комментарий от TDrive

Все это активно используется в динамических яп.

Да, но выглядит совершенно по другому. Обычно просто хватает передать функцию. Без интерфейсов и имплементаций. Я не против того что паттерны проектирования как словарик разработчика нужны. Просто их каноничная™ книжная реализация обычно содержит слишком много возни с системой типов, first class functions много проблем убирают и большинство паттернов реализуется тривиальнейшим образом.

anonymous
()
Ответ на: комментарий от anonymous

Настолько тривиальнейшим, что новички начинает писать паттернами даже не подозревая об этом.

anonymous
()
Ответ на: комментарий от anonymous

Просто их каноничная™ книжная реализация обычно содержит слишком много возни с системой типов

Их каноничная книжная реализация включает реализацию на smalltalk.

TDrive ★★★★★
()
Ответ на: комментарий от TDrive

Их каноничная книжная реализация включает реализацию на smalltalk.

Провал, надо будет ознакомиться, я советское издание читал.

anonymous
()

Этот шаблон придумали в языках без первоклассных функций. Потому-то в джс он не нужен. Ты в джаве 6 напиши.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.