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

Мы начнем с работы над примером без шаблона разработки стратегии.

Допустим, мы работаем над банковским приложением. В нашем банковском приложении есть класс «Клиент». В нашем классе Customer у нас есть три метода, которые возвращают номер сберегательного счета, один тип возврата кредита и одну процентную ставку возврата кредита.

class Customer{
 String getSavingAccountNumber{}
 String getLoanType(){}
 double getLoanInterestRate(){}}

Теперь, если мы хотим иметь клиента, у которого есть жилищный кредит. Мы можем расширить класс Customer

class HomeLoanCustomer extend Customer{
 String getLoanType(){
return "This a home loan"
}
 double getLoanInterestRate(){
return 8.16
}
}

Таким же образом мы можем создать CarLoanCustomer. Но как насчет клиента, у которого нет ссуды, например NoLoanCustomer или RichCustomer, но у него все еще есть getLoanType, getLoanInterestRate выставленный ему метод. Вы можете возразить, что я могу переопределить эти методы, которые ничего не возвращают. Но вопрос в том, во сколько? Каждый раз, когда банк решает добавить новый тип клиента, мы должны переопределить эти методы, убедившись, что мы не возвращаем процентную ставку по ссуде и тип ссуды клиентам, которым эти методы вообще не требуются.

Теперь одно из возможных решений - использовать интерфейс. Нравится

interface LoanCustomer{
 String getSavingAccountNumber
 String getLoanType()
}
class Customer{
 String getSavingAccountNumber{}
}
class HomeLoanCustomer extend Customer implements LoanCustomer {
 String getLoanType(){
return "This a home loan"
}
 double getLoanInterestRate(){
return 8.16
}
class CarLoanCustomer extend Customer implements LoanCustomer {
 String getLoanType(){
return "This a car loan"
}
void double getLoanInterestRate(){
return 11.89
}
class RichCustomer extends Customer{}

Как видите, RichCustomer не требует реализации LoanCustomer.
Но вот загвоздка. А как насчет повторного использования кода? Предположим, что если вы хотите что-то изменить в интерфейсе LoanCustomer, вам нужно изменить все клиенты ссуды, которые это реализуют. Итак, мы пришли к выводу, что наш код не работает, когда дело доходит до изменений. Потому что программное обеспечение обязательно изменится в будущем.

Теперь мы воспользуемся шаблоном стратегии стратегии для решения проблемы.

Теперь это наш базовый класс

class Customer{
 String getSavingAccountNumber{}
 String getLoanType(){}
 double getLoanInterestRate(){}}

Здесь мы должны выяснить, какой алгоритм меняется, а какой остается. В классе клиентов алгоритм getSavingAccountNumber остается неизменным для всех клиентов, потому что, согласно правилам банка, каждый клиент должен иметь сберегательный счет, чтобы пользоваться услугами банка. А алгоритм getLoanType, getLoanInterestRate варьируется от клиента к клиенту.

Итак, в соответствии с шаблоном стратегии нам необходимо инкапсулировать изменяющийся алгоритм. Итак, мы инкапсулируем их в интерфейс или класс и реализуем его семейство алгоритмов.

interface Loanable{
 String getLoanType()
 double getLoanInterestRate()
}
class HomeLoan implements Loanable{
 String getLoanType() // home loan
 double getLoanInterestRate() //8.9
}
class CarLoan implements Loanable{
 String getLoanType() // car loan
 double getLoanInterestRate() //12.95
}
class NoLoan implements Loanable{
 String getLoanType() // no loan
 double getLoanInterestRate() //0.0
}

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

class Customer{
Loanable loanable;
 String getSavingAccountNumber{}
 String loanType(){loanable.getLoanType()}
 double loanInterestRate(){loanable.getLoanInterestRate()}
}
class HomeLoanCustomer extends Customer{
public HomeLoanCustomer(){
loanable=new HomeLoan()
}
}
class NoLoanCustomer extends Customer{
public HomeLoanCustomer(){
loanable=new NoLoan()
}
}
class RichCustomer extends Customer{
public HomeLoanCustomer(){
loanable=new NoLoan()
}
}

Теперь, если вы хотите добавить новую функциональность для клиентов, у которых нет ссуды, скажем, банк хочет показать промо, которое гласит: «Получите ссуду с нулевой комиссией за обработку». Мы можем изменить наш класс NoLoan, не затрагивая клиентов. Нравится:

class NoLoan implements Loanable{
 String getLoanType() // no loan
 double getLoanInterestRate() //0.0
 void showPromo() //get loan with zero processing fee
}

А наш класс HomeLoan вроде этого:

class HomeLoan implements Loanable{
 String getLoanType() // home loan
 double getLoanInterestRate() //5.5 (Home loan now get cheaper)
}

Таким образом, наш код готов к внесению изменений, и его можно будет сопровождать. Если банк захочет, в будущем мы сможем добавить новый вид кредита.

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

Шаблон стратегии = инкапсуляция различных алгоритмов + композиция