23种设计模式之策略模式(20)

tech2025-02-06  11

面向对象编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。

策略模式(Strategy):他定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到使用算法的客户。

策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,他可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。

策略模式的Strangy类层次为context定义了一系列可供重用的算法或行为。继承有助于析取出这些算法中的公共功能。

策略模式的优点是简化了单元测试,因为每个算法都有自己的类,可以通过自己的接口单独测试。

当不同的行为堆砌在一个类中时,就很难避免使用条件语句来选择合适的行为。将这些行为封装在一个个独立的stratege类中,可以在使用这些行为的类中消除条件语句。

策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。

在基本的策略模式中选择所用具体实现的职责由客户端对象承担,并转给策略模式的Context对象。

任何需求的变更都是需要成本的。

对同一件事的不同处理方式,本章是的这一件事指的是排序,对数组,对猫,对狗,对猫的体重,对猫的身高进行排序。

在需求一步一步被提出的时候,代码的可扩展性如何做到最好。

Context.java

public class Context { Strategy strategy; public Context(Strategy strategy) { this.strategy = strategy; } //上下文接口 public void ContextInterface() { strategy.AlgorithmInterface(); } }

Strategy.java

public abstract class Strategy { //算法方法 public abstract void AlgorithmInterface(); }

ConcreteStrategyA.java

public class ConcreteStrategyA extends Strategy { @Override public void AlgorithmInterface() { System.out.println("换成绿皮皮"); } }

ConcreteStrategyB.java

public class ConcreteStrategyB extends Strategy { @Override public void AlgorithmInterface() { System.out.println("换成黄皮皮"); } }

ConcreteStrategyC.java

public class ConcreteStrategyC extends Strategy { @Override public void AlgorithmInterface() { System.out.println("换成蓝皮皮"); } }

StrategyMain .java

public class StrategyMain { public static void main(String[] args) { Context context; context = new Context(new ConcreteStrategyA()); context.ContextInterface(); context = new Context(new ConcreteStrategyB()); context.ContextInterface(); context = new Context(new ConcreteStrategyC()); context.ContextInterface(); } }
1在最开始有一个对数组进行排序的需求。。

Main.java

public class Main { public static void main(String[] args) { int[] a = {9,2,3,5,7,1,4}; Sorter sorter = new Sorter(); sorter.sort(a); System.out.println(Arrays.toString(a)); } }

Sort.java

public class Sorter { public static void sort(int[] arr) { for(int i=0;i<arr.length;i++) { int minPos = i; for (int j = i+1; j < arr.length; j++) { minPos = arr[j]<arr[minPos] ? j :minPos; } swap(arr,i,minPos); } } static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i]= arr[j]; arr[j]= temp; } }
2后来需要对猫(体重)进行排序

Main.java

public class Main { public static void main(String[] args) { // int[] a = {9,2,3,5,7,1,4}; Cat[] cats = {new Cat(5, 5), new Cat(3, 3), new Cat(7, 7)}; Sorter sorter = new Sorter(); sorter.sort(cats); System.out.println(Arrays.toString(cats)); } }

Sort.java

public class Sorter { public static void sort(Cat[] arr) { for(int i=0;i<arr.length;i++) { int minPos = i; for (int j = i+1; j < arr.length; j++) { minPos = arr[j].compareTo(arr[minPos]) == -1 ? j :minPos; } swap(arr,i,minPos); } } static void swap(Cat[] arr, int i, int j) { Cat temp = arr[i]; arr[i]= arr[j]; arr[j]= temp; } }

Cat.java

public class Cat { int weight,height; public Cat(int weight, int height) { super(); this.weight = weight; this.height = height; } public int compareTo(Cat c) { if(this.weight < c.weight) return -1; else if(this.weight > c.weight) return 1; else return 0; } @Override public String toString() { return "Cat [weight=" + weight + ", height=" + height + "]"; } }
3再后来需要对狗进行排序

Main.java

public class Main { public static void main(String[] args) { //Cat[] cats = {new Cat(5, 5), new Cat(3, 3), new Cat(7, 7)}; Dog[] dogs = {new Dog(3),new Dog(5),new Dog(1)}; Sorter sorter = new Sorter(); sorter.sort(dogs); System.out.println(Arrays.toString(cats)); }

Cat.java

public class Cat implements Compareble{ int weight,height; public Cat(int weight, int height) { super(); this.weight = weight; this.height = height; } public int compareTo(Object o) { Cat c = (Cat)o; if(this.weight < c.weight) return -1; else if(this.weight > c.weight) return 1; else return 0; } @Override public String toString() { return "Cat [weight=" + weight + ", height=" + height + "]"; } }

Dog.java

public class Dog implements Compareble{ int food; public Dog(int food) { super(); this.food = food; } @Override public int compareTo(Object o) { Dog dog = (Dog)o; if(this.food < dog.food) return -1; else if(this.food > dog.food) return 1; else return 0; } @Override public String toString() { return "Dog [food=" + food + "]"; }; }

Sorter.java

public class Sorter { public static void sort(Comparable[] arr) { for(int i=0;i<arr.length;i++) { int minPos = i; for (int j = i+1; j < arr.length; j++) { minPos = arr[j].compareTo(arr[minPos]) == -1 ? j :minPos; } swap(arr,i,minPos); } } static void swap(Comparable[] arr, int i, int j) { Comparable temp = arr[i]; arr[i]= arr[j]; arr[j]= temp; } }

Comparable.java

public interface Comparable<T> { public int compareTo(T o); }
4再再后来需要对猫的身高进行排序

把比较器单独作为一个类使用,这样修改比较方式的时候就不用更改源代码,仅需增加一个方法即可

Main,java

public class Main { public static void main(String[] args) { Dog[] dogs = {new Dog(3),new Dog(5),new Dog(1)}; Sorter sorter = new Sorter(); sorter.sort(dogs,new DogComparator()); System.out.println(Arrays.toString(dogs)); Cat[] cats = {new Cat(5, 2), new Cat(3, 5), new Cat(7, 1)}; Sorter<Cat> sorter2 = new Sorter<Cat>(); Sorter.sort(cats,new CatWeightComparator()); System.out.println("使用CatWeightComparator比较器对猫进行排序:"); System.out.println(Arrays.toString(cats)); Sorter.sort(cats,new CatHeightComparator()); System.out.println("使用CatHeightComparator比较器对猫进行排序:"); System.out.println(Arrays.toString(cats)); Sorter.sort(cats,(c1,c2) -> { if(c1.weight < c2.weight) return -1; else if(c1.weight > c2.weight) return 1; else return 0; }); //这里使用lambad表达式仅是对lambda表达式的练习,这样写对策略模式并不匹配 System.out.println("使用Lambad表达式对猫(体重)进行排序:"); System.out.println(Arrays.toString(cats)); } }

Cat.java

public class Cat{ int weight,height; public Cat(int weight, int height) { super(); this.weight = weight; this.height = height; } @Override public String toString() { return "Cat [weight=" + weight + ", height=" + height + "]"; } }

Dog.java

public class Dog { int food; public Dog(int food) { super(); this.food = food; } @Override public String toString() { return "Dog [food=" + food + "]"; }; }

Sorter.java

public class Sorter<T> { public static<T> void sort(T[] arr,Comparator<T> comparator) { for(int i=0;i<arr.length;i++) { int minPos = i; for (int j = i+1; j < arr.length; j++) { minPos = comparator.compare​(arr[j],arr[minPos]) == -1 ? j :minPos; } swap(arr,i,minPos); } } static<T> void swap(T[] arr, int i, int j) { T temp = arr[i]; arr[i]= arr[j]; arr[j]= temp; } }

comparator.java

@FunctionalInterface // 函数式接口仅有一个抽象方法,但可有多个default方法 public interface Comparator<T> { int compare​(T o1,T o2); //这个方法与代码内容无关 default void m() { System.out.println("m"); } }

DogComparator.java

public class DogComparator implements Comparator<Dog> { public int compare​(Dog d1,Dog d2) { if(d1.food < d2.food) return -1; else if(d1.food > d2.food) return 1; else return 0; } }

CatWeightComparator.java

public class CatWeightComparator implements Comparator<Cat> { public int compare​(Cat c1,Cat c2) { if(c1.weight < c2.weight) return -1; else if(c1.weight > c2.weight) return 1; else return 0; } }

CatHeightComparator.java

public class CatHeightComparator implements Comparator<Cat> { public int compare​(Cat c1,Cat c2) { if(c1.height < c2.height) return -1; else if(c1.height > c2.height) return 1; else return 0; } }

为什么要有这个(默认方法)特性?

首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。

singleton - spring的bean工厂

https://docs.oracle.com/en/java/javase/14/docs/api/index.html

最新回复(0)