предисловие
[Разблокировать новые позы] Брат деи, ваш код нужно оптимизировать
Как упоминалось в предыдущей статье, простойif-else
,можно использовать卫语句
оптимизировать. Однако в реальной разработке зачастую бывает не простоif-else
структура, мы обычно不经意间
Напишите следующий код:
-------------------- 理想中的 if-else --------------------
public void today() {
if (isWeekend()) {
System.out.println("玩游戏");
} else {
System.out.println("上班!");
}
}
-------------------- 现实中的 if-else --------------------
if (money >= 1000) {
if (type == UserType.SILVER_VIP.getCode()) {
System.out.println("白银会员 优惠50元");
result = money - 50;
} else if (type == UserType.GOLD_VIP.getCode()) {
System.out.println("黄金会员 8折");
result = money * 0.8;
} else if (type == UserType.PLATINUM_VIP.getCode()) {
System.out.println("白金会员 优惠50元,再打7折");
result = (money - 50) * 0.7;
} else {
System.out.println("普通会员 不打折");
result = money;
}
}
//省略 n 个 if-else ......
Не будет преувеличением сказать, что все мы писали похожий код, вспоминая, какif-else
Из-за страха господства мы часто ничего не делаем или даже отпускаем.
Позвольте мне поделиться сложностями, с которыми я столкнулся при разработкеif-else
утверждение“优雅处理”
идеи. Если что-то не так, пожалуйста, поделитесь и изучите вместе.
необходимость
Допустим есть такое требование:
Система электронной коммерции, когда пользователи потребляют满1000
Сумма может быть снижена в зависимости от VIP-уровня пользователя.
По VIP-уровню пользователя рассчитывается окончательная стоимость пользователя.
- Обычные участники не делают скидки
- Скидка серебряному участнику 50 юаней
- Золотой участник скидка 20%
- Платиновые участники экономят 50 юаней, затем скидка 30%
Реализация кодирования
private static double getResult(long money, int type) {
double result = money;
if (money >= 1000) {
if (type == UserType.SILVER_VIP.getCode()) {
System.out.println("白银会员 优惠50元");
result = money - 50;
} else if (type == UserType.GOLD_VIP.getCode()) {
System.out.println("黄金会员 8折");
result = money * 0.8;
} else if (type == UserType.PLATINUM_VIP.getCode()) {
System.out.println("白金会员 优惠50元,再打7折");
result = (money - 50) * 0.7;
} else {
System.out.println("普通会员 不打折");
result = money;
}
}
return result;
}
Для удобства демонстрации я сделал простую реализацию в коде, но на самом делеif - else
будет осуществляться复杂的逻辑
выставление счетов.
Функционально он в основном завершен, но для человека вроде меня, помешанного на чистоте кода, качество кода не может вынести прямого взгляда на него. мы начинаем优化
посмотри на наш第一版代码
Бар.
считать
Увидев приведенный выше код, первая мысль умных друзей, что это нетипично策略模式
?
Вы такой умный парень, давайте сначала попробуем оптимизировать код с помощью шаблона стратегии.
режим стратегии
Что такое режим стратегии?
Некоторым друзьям может быть непонятно, что такое режим стратегии. Шаблон стратегии состоит в том, чтобы определить ряд алгоритмов, расположив их один за другим.封装
и сделать их взаимно совместимыми替换
.
Например, указанные выше требования返利
,имеют打折
,имеют折上折
и Т. Д. Эти алгоритмы сами по себе策略
. и эти алгоритмы могут взаимодействовать друг с другом替换
Да, как сегодня я хочу白银会员优惠50
, который можно заменить завтра на白银会员打9折
.
Сказав так много, лучше закодировать.
кодирование
public interface Strategy {
// 计费方法
double compute(long money);
}
// 普通会员策略
public class OrdinaryStrategy implements Strategy {
@Override
public double compute(long money) {
System.out.println("普通会员 不打折");
return money;
}
}
// 白银会员策略
public class SilverStrategy implements Strategy {
@Override
public double compute(long money) {
System.out.println("白银会员 优惠50元");
return money - 50;
}
}
// 黄金会员策略
public class GoldStrategy implements Strategy{
@Override
public double compute(long money) {
System.out.println("黄金会员 8折");
return money * 0.8;
}
}
// 白金会员策略
public class PlatinumStrategy implements Strategy {
@Override
public double compute(long money) {
System.out.println("白金会员 优惠50元,再打7折");
return (money - 50) * 0.7;
}
}
мы определяемStrategy
интерфейс и определить четыре подкласса, которые реализуют интерфейс. в соответствующемcompute
Метод Реализовать логику начисления платы собственной политики.
private static double getResult(long money, int type) {
double result = money;
if (money >= 1000) {
if (type == UserType.SILVER_VIP.getCode()) {
result = new SilverStrategy().compute(money);
} else if (type == UserType.GOLD_VIP.getCode()) {
result = new GoldStrategy().compute(money);
} else if (type == UserType.PLATINUM_VIP.getCode()) {
result = new PlatinumStrategy().compute(money);
} else {
result = new OrdinaryStrategy().compute(money);
}
}
return result;
}
затем соответствоватьgetResult
метод, согласноtype
Замените соответствующим VIP-пользователем策略
.
В этом коде появляются повторяющиеся вызовыcompute
, мы можем попытаться оптимизировать дальше.
private static double getResult(long money, int type) {
if (money < 1000) {
return money;
}
Strategy strategy;
if (type == UserType.SILVER_VIP.getCode()) {
strategy = new SilverStrategy();
} else if (type == UserType.GOLD_VIP.getCode()) {
strategy = new GoldStrategy();
} else if (type == UserType.PLATINUM_VIP.getCode()) {
strategy = new PlatinumStrategy();
} else {
strategy = new OrdinaryStrategy();
}
return strategy.compute(money);
}
помнишь, я былпервый разупоминается в卫语句
? Мы возвращаемся рано за деньги 满1000逻辑, а также для уменьшения ненужных отступов.
обдумывать
В какой-то момент я подумал, что режим стратегии — это не что иное, как это. Я думал, что код был оптимизирован до этого момента.
Но есть еще одна ужасная вещь,if-else
Все-еще существует :)
Я пытался пролистать много книг, чтобы увидеть, как избавиться от режима стратегии.if-else
Большинство методов в книге используют шаблон Simple Factory + Strategy. Пучокif - else
переключить наswitch
Просто создайте фабричный метод.
Но это далеко не то, что я хочу, внизif - else
Пока однажды ночью мой босс не поделилсяJava8
Когда дело доходит до небольших навыков, это открывает новый мир.
Фабрика + Стратегия
public interface Strategy {
double compute(long money);
// 返回 type
int getType();
}
public class OrdinaryStrategy implements Strategy {
@Override
public double compute(long money) {
System.out.println("普通会员 不打折");
return money;
}
// 添加 type 返回
@Override
public int getType() {
return UserType.SILVER_VIP.getCode();
}
}
public class SilverStrategy implements Strategy {
@Override
public double compute(long money) {
System.out.println("白银会员 优惠50元");
return money - 50;
}
// type 返回
@Override
public int getType() {
return UserType.SILVER_VIP.getCode();
}
}
....省略剩下 Strategy
Добавим новый в СтратегиюgetType
метод использования标示
этой стратегииtype
ценность. Код относительно прост, поэтому я не буду вводить здесь слишком много.
public class StrategyFactory {
private Map<Integer, Strategy> map;
public StrategyFactory() {
List<Strategy> strategies = new ArrayList<>();
strategies.add(new OrdinaryStrategy());
strategies.add(new SilverStrategy());
strategies.add(new GoldStrategy());
strategies.add(new PlatinumStrategy());
strategies.add(new PlatinumStrategy());
// 看这里 看这里 看这里!
map = strategies.stream().collect(Collectors.toMap(Strategy::getType, strategy -> strategy));
/* 等同上面
map = new HashMap<>();
for (Strategy strategy : strategies) {
map.put(strategy.getType(), strategy);
}*/
}
public static class Holder {
public static StrategyFactory instance = new StrategyFactory();
}
public static StrategyFactory getInstance() {
return Holder.instance;
}
public Strategy get(Integer type) {
return map.get(type);
}
}
Одноэлементный статический внутренний класс, тип реализации одноэлементного шаблона, не является предметом этой статьи.Если вы не понимаете этого, вы можете сделать это самостоятельно.
Приступаем к созданию другогоStrategyFactory
Заводской класс. StrategyFactory здесь я использую静态内部类单例
, при построении метода инициализировать требуемыйStrategy
, и положиlist
превратиться вmap
.
Здесь преобразование“灵魂”
где.
toMap
Давайте сначала посмотримJava8
Маленькая хитрость в грамматике.
Обычно мы перебираем список вручнуюput
в Карту.
-------------- before -----------------
map = new HashMap<>();
for (Strategy strategy : strategies) {
map.put(strategy.getType(), strategy);
}
-------------- after Java8 -----------------
map = strategies.stream().collect(Collectors.toMap(Strategy::getType, strategy -> strategy));
toMap
Первый параметр — это Функция, соответствующая карте вkey
, второй параметр тоже Функция, стратегия -> стратегия, слеваstrategy
состоит в том, чтобы пройти каждую стратегию в стратегиях, правильныхstrategy
Карта соответствуетvalue
ценность.
Если вы не понимаете
Java8
Друзья грамматики, настоятельно рекомендуем посмотреть"Java8 实战
, который подробно описан в книгеLambda
выражение,Stream
и т.д. синтаксис.
Эффект
private static double getResult(long money, int type) {
if (money < 1000) {
return money;
}
Strategy strategy = StrategyFactory.getInstance().get(type);
if (strategy == null){
throw new IllegalArgumentException("please input right type");
}
return strategy.compute(money);
}
До сих пор, через заводской класс, в нашемgetResult()
При звонке, по входящемуtype
, вы можете получить соответствующийStrategy
больше не страшноif-else
утверждение.
Готовая разброска цветов :)
следовать за
Для последующей оптимизации кода, если это Java-проект, можно попробовать использовать自定义注解
, аннотируйте класс реализации стратегии.
Это может упростить первоначальную необходимость добавления списка фабричных классов.Stratey 策略
.
Наконец
Выше это то, с чем я столкнулся при разработке сложныхif-else
утверждение“优雅处理”
Если с вашими идеями что-то не так, вы можете обменяться ими и поучиться вместе.