일상적인 개발에서 우리는 함수를 구현하기 위해 많은 알고리즘이나 전략이 있는 상황에 자주 직면합니다. 우리는 다양한 알고리즘이나 전략을 기반으로 이 기능을 구현할 수 있습니다. 예: 물류 계산 방법을 계산하려면 모두 청구됩니다. 특급 배송마다 JD Express, Best Express 및 YTO Express와 같은 청구 방법이 다릅니다. 배송비를 계산하는 방식이 다릅니다. 그렇다면 어떻게 달성할 수 있을까요? 간단한 것은 if...else...또는 switch...case...입니다. 이 두 가지 구현을 하드 코딩이라고 합니다. Yunda Express와 같은 새로운 청구 방법이 있는 경우 알고리즘의 소스 코드를 수정해야 합니다. 이로 인해 코드가 비대해지고 유지 관리가 어려워집니다.
그래서 우리가 달성해야 할 것은 각각 고유한 알고리즘이 있고 클라이언트에서 호출할 메서드만 선택하면 된다는 것입니다.
Environment 클래스(Context): ConcreteStrategy 객체로 구성됩니다. Strategy 개체에 대한 참조를 유지합니다. Strategy가 해당 데이터에 액세스할 수 있도록 인터페이스를 정의할 수 있습니다.
추상 전략 클래스(Strategy): 지원되는 모든 알고리즘의 공개 인터페이스를 정의합니다. 컨텍스트는 이 인터페이스를 사용하여 ConcreteStrategy에 의해 정의된 알고리즘을 호출합니다.
Concrete Strategy 클래스(ConcreteStrategy): Strategy 인터페이스를 사용하여 특정 알고리즘을 구현합니다.
다양한 특송 회사의 운임을 예로 들어보세요.
1단계: 추상 전략 클래스 정의(청구 방법)
public interface CommandStrategy { /** * 计费方式 * @param message */ void calMoney(String message); }
2단계: 특정 전략 클래스 정의(다양한 알고리즘 클래스가 이를 구현함) 인터페이스)
public class BaiShiCommand implements CommandStrategy { /** * 百世快递计费方式 * @param message */ @Override public void calMoney(String message) { System.out.println("百世快递收费方式:"+"起步20,每公斤6元"); } }
public class JingDongCommand implements CommandStrategy { /** * 京东快递计费方式 * @param message */ @Override public void calMoney(String message) { System.out.println("京东快递收费方式:"+"起步30,每公斤5元"); } }
public class YuanTongCommand implements CommandStrategy { /** * 圆通快递计费方式 * @param message */ @Override public void calMoney(String message) { System.out.println("圆通快递收费方式:"+"起步10,每公斤8元"); } }
3단계: 환경 클래스 정의
public class CommandContext { public CommandStrategy getInstance(String commandType) { CommandStrategy commandStrategy = null; Map<String, String> allClazz = CommandEnum.getAllClazz(); //拿到对应算法类对应的路径 String clazz = allClazz.get(commandType.trim().toLowerCase()); if (StringUtils.isNotEmpty(clazz)) { try { try { //创建一个对象实例 commandStrategy = (CommandStrategy) Class.forName(clazz).newInstance();//调用无参构造器创建实例 } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } System.out.println("commandStrategy:"+commandStrategy); return commandStrategy; } }
열거 클래스 정의:
public enum CommandEnum { JingDong("京东", "com.liubujun.design.command.JingDongCommand"), BaiShi("百世", "com.liubujun.design.command.BaishiCommand"), YuanTong("圆通", "com.liubujun.design.command.YuanTongCommand"); private String name; private String clazz; public static Map<String, String> getAllClazz() { Map<String, String> map = new HashMap<>(8); System.out.println("==================="+Arrays.toString(CommandEnum.values())+"================"); for (CommandEnum commandEnum : CommandEnum.values()) { map.put(commandEnum.getCommand(), commandEnum.getClazz()); } return map; } public String getCommand() { return name; } CommandEnum(String command, String clazz) { this.name = command; this.clazz = clazz; } public void setCommand(String command) { this.name = command; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } }
Client:
public class MainStart { public static void main(String[] args) { String message = "京东"; CommandContext commandContext = new CommandContext(); //拿到message对应算法的对象实例 CommandStrategy commandStrategy = commandContext.getInstance(message); commandStrategy.calMoney(message); } }
이런 식으로 클라이언트는 어떤 특급 청구 방법을 직접 호출할 수 있습니다
장점:
1) 관련 알고리즘 시리즈 전략 클래스 계층 구조는 컨텍스트에 대한 일련의 재사용 가능한 알고리즘 또는 동작을 정의합니다. 상속은 이러한 알고리즘에서 공통 기능을 추출하는 데 도움이 됩니다.
2) 상속 관계를 대체하는 방법 제공: 상속은 여러 알고리즘이나 동작을 지원하는 또 다른 방법을 제공합니다. Context 클래스를 직접 하위 클래스화하여 다른 동작을 제공할 수 있습니다. 그러나 이렇게 하면 동작을 컨텍스트에 하드 코딩하고 알고리즘 구현과 컨텍스트 구현을 혼합하여 컨텍스트를 이해, 유지 관리 및 확장하기 어렵게 만들고 알고리즘을 동적으로 변경할 수 없습니다. 결국에는 관련된 클래스가 많이 생기고, 이들 사이의 유일한 차이점은 그들이 사용하는 알고리즘이나 동작입니다. 독립적인 전략 클래스에 알고리즘을 캡슐화하면 해당 컨텍스트와 독립적으로 알고리즘을 변경할 수 있으므로 전환, 이해 및 확장이 쉬워집니다.
3) 일부 if else 조건문 제거: 전략 모드는 조건문을 사용하여 원하는 동작을 선택하는 대신 대안을 제공합니다. 클래스에 다양한 동작이 쌓이면 적절한 동작을 선택하기 위해 조건문을 사용하지 않는 것이 어렵습니다. 별도의 Strategy 클래스에 동작을 캡슐화하면 이러한 조건문이 제거됩니다. 조건문이 많은 코드는 일반적으로 전략 모드를 사용해야 함을 나타냅니다.
4) 구현 선택 전략 모드는 동일한 동작에 대해 다양한 구현을 제공할 수 있습니다. 고객은 다양한 시간/공간 절충 요구 사항에 따라 다양한 전략 중에서 선택할 수 있습니다.
단점:
1) 고객은 모든 전략 클래스를 알아야 하고 어떤 전략 클래스를 사용할지 결정해야 합니다. 이 모델에는 잠재적인 단점이 있습니다. 즉, 고객이 적합한 전략을 선택하려면 이러한 전략이 무엇인지 알아야 합니다. 정말 큰 차이가 있어요. 이 시점에서 특정 구현 문제가 고객에게 노출되어야 할 수도 있습니다. 따라서 전략 모드는 이러한 다양한 행동 변형이 고객 행동과 관련된 경우에만 필요합니다.
2) 전략과 컨텍스트 간의 통신 오버헤드: 각 ConcreteStrategy에 의해 구현된 알고리즘이 단순하든 복잡하든 상관없이 모두 Strategy에서 정의한 인터페이스를 공유합니다. 따라서 일부 ConcreteStrategy는 이 인터페이스를 통해 전달된 모든 정보를 사용하지 않을 수 있습니다. 간단한 ConcreteStrategy는 어떤 정보도 사용하지 않을 수 있습니다. 이는 때때로 컨텍스트가 결코 사용되지 않을 매개변수를 생성하고 초기화한다는 것을 의미합니다. 그러한 문제가 존재한다면 전략과 컨텍스트 간의 보다 긴밀한 결합이 필요할 것입니다.
3) 전략 패턴을 사용하면 많은 전략 클래스가 생성됩니다. 플라이웨이트 패턴을 사용하면 개체 수를 어느 정도 줄일 수 있습니다. 개체 수 증가 전략은 응용 프로그램의 개체 수를 늘립니다. 때로는 다양한 컨텍스트에서 공유할 수 있는 상태 비저장 객체로 전략을 구현하여 이러한 오버헤드를 줄일 수 있습니다. 나머지 상태는 컨텍스트에 의해 유지됩니다. 컨텍스트는 Strategy 개체에 대한 모든 요청에서 이 상태를 전달합니다. 공유 전략은 호출 간 상태를 유지해서는 안 됩니다.
위 내용은 Java 디자인 패턴의 전략 패턴 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!