策略模式(strategy):定義一組算法,將每一個算法都封裝起來,而且使它們之間能夠互換。java
商城搞多種優惠活動,顧客只能參與其中一種優惠算法。
算法
類圖
spring
FullDistcount
滿200減20元;FirstPurchaseDiscount
首次購買減20元;SecondPurchaseDiscount
第二件打9折;HolidayDiscount
節日一概減5元.代碼實現以下,環境類數組
package com.wzj.strategy; /** * @Author: wzj * @Date: 2020/5/5 21:25 * @Desc: 優惠類:環境類 */ public class Context { private int price; private Discount discount; public Context(int price, Discount discount) { this.price = price; this.discount = discount; } public int getPrice() { return this.discount.calculateBySourcePrice(this.price); } }
折扣接口類app
package com.wzj.strategy; /** * @Author: wzj * @Date: 2020/5/5 20:56 * @Desc: 折扣優惠接口 */ public interface Discount { public int calculateBySourcePrice(int price); }
滿減優惠ide
package com.wzj.strategy; /** * @Author: wzj * @Date: 2020/5/5 20:57 * @Desc: 優惠滿減20元 */ public class FullDiscount implements Discount { @Override public int calculateBySourcePrice(int price) { if (price > 200){ System.out.println("優惠滿減20元"); price = price - 20; } return price; } }
首次優惠類函數
package com.wzj.strategy; /** * @Author: wzj * @Date: 2020/5/5 21:11 * @Desc: 首次購買減20元 */ public class FirstPurchaseDiscount implements Discount { @Override public int calculateBySourcePrice(int price) { if (price > 100){ System.out.println("首次購買減20元"); price = price - 20; } return price; } }
第二件優惠類測試
package com.wzj.strategy; /** * @Author: wzj * @Date: 2020/5/5 21:05 * @Desc: 第二件打9折 */ public class SecondPurchaseDiscount implements Discount { @Override public int calculateBySourcePrice(int price) { System.out.println("第二件打9折"); Double balance = price * 0.9; return balance.intValue(); } }
節假日優惠類ui
package com.wzj.strategy; /** * @Author: wzj * @Date: 2020/5/5 21:09 * @Desc: 節日一概減5元 */ public class HolidayDiscount implements Discount { @Override public int calculateBySourcePrice(int price) { if (price > 20){ System.out.println("節日一概減5元"); price = price - 5; } return price; } }
測試類this
package com.wzj.strategy; /** * @Author: wzj * @Date: 2020/5/5 21:35 * @Desc: 測試類 */ public class TestStrategy { public static void main(String[] args) { Discount discount = new FirstPurchaseDiscount(); Context context = new Context(110, discount); int price = context.getPrice(); System.out.println(price); } }
結果
首次購買減20元 90
Comparable,在jdk1.8中描述以下,實現該接口的對象的List和array,能夠經過Collections.sort和Arrays.sort自動排序,該對象具有sorted map的key和sorted set的元素的特徵。
源碼解析
public interface Comparable<T> { public int compareTo(T o); }
該接口實現一個抽象方法compareTo,定義兩個對象的比較方式,返回值大於0、等於0、小於0,分別表示當前對象與傳入對象的關係爲大於、相等、小於。
Comparator爲比較器,它能夠做爲一個參數傳遞到Collections.sort和Arrays.sort方法來指定某個類對象的排序方式。同時它也能爲sorted set和sorted map指定排序方式。
源碼解析
@FunctionalInterface public interface Comparator<T> { // 惟一的抽象方法,用於定義比較方式(即排序方式) // o1>o2,返回1;o1=o2,返回0;o1<o2,返回-1 int compare(T o1, T o2); boolean equals(Object obj); // 1.8新增的默認方法:用於反序排列 default Comparator<T> reversed() { return Collections.reverseOrder(this); } // 1.8新增的默認方法:用於構建一個次級比較器,當前比較器比較結果爲0,則使用次級比較器比較 default Comparator<T> thenComparing(Comparator<? super T> other) { Objects.requireNonNull(other); return (Comparator<T> & Serializable) (c1, c2) -> { int res = compare(c1, c2); return (res != 0) ? res : other.compare(c1, c2); }; } // 1.8新增默認方法:指定次級比較器的 // keyExtractor表示鍵提取器,定義提取方式 // keyComparator表示鍵比較器,定義比較方式 default <U> Comparator<T> thenComparing( Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) { return thenComparing(comparing(keyExtractor, keyComparator)); } // 1.8新增默認方法:用於執行鍵的比較,採用的是由鍵對象內置的比較方式 default <U extends Comparable<? super U>> Comparator<T> thenComparing( Function<? super T, ? extends U> keyExtractor) { return thenComparing(comparing(keyExtractor)); } // 1.8新增默認方法:用於比較執行int類型的鍵的比較 default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) { return thenComparing(comparingInt(keyExtractor)); } // 1.8新增默認方法:用於比較執行long類型的鍵的比較 default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) { return thenComparing(comparingLong(keyExtractor)); } // 1.8新增默認方法:用於比較執行double類型的鍵的比較 default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) { return thenComparing(comparingDouble(keyExtractor)); } // 1.8新增靜態方法:用於獲得一個相反的排序的比較器,這裏針對的是內置的排序方式(即繼承Comparable) public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() { return Collections.reverseOrder(); } // 1.8新增靜態方法:用於獲得一個實現了Comparable接口的類的比較方式的比較器 // 簡言之就是將Comparable定義的比較方式使用Comparator實現 @SuppressWarnings("unchecked") public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() { return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE; } // 1.8新增靜態方法:獲得一個null親和的比較器,null小於非null,兩個null相等,若是全不是null, // 則使用指定的比較器比較,若未指定比較器,則非null所有相等返回0 public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) { return new Comparators.NullComparator<>(true, comparator); } // 1.8新增靜態方法:獲得一個null親和的比較器,null大於非null,兩個null相等,若是全不是null, // 則使用指定的比較器比較,若未指定比較器,則非null所有相等返回0 public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) { return new Comparators.NullComparator<>(false, comparator); } // 1.8新增靜態方法:使用指定的鍵比較器用於執行鍵的比較 public static <T, U> Comparator<T> comparing( Function<? super T, ? extends U> keyExtractor, Comparator<? super U> keyComparator) { Objects.requireNonNull(keyExtractor); Objects.requireNonNull(keyComparator); return (Comparator<T> & Serializable) (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2)); } // 1.8新增靜態方法:執行鍵比較,採用內置比較方式,key的類必須實現Comparable public static <T, U extends Comparable<? super U>> Comparator<T> comparing( Function<? super T, ? extends U> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); } // 1.8新增靜態方法:用於int類型鍵的比較 public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); } // 1.8新增靜態方法:用於long類型鍵的比較 public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); } // 1.8新增靜態方法:用於double類型鍵的比較 public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) { Objects.requireNonNull(keyExtractor); return (Comparator<T> & Serializable) (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); } }
JDK1.8以前,Comparator中只要兩個方法,就是前兩個方法,後面的全部默認方法均爲1.8新增的方法,採用的是1.8新增的功能:接口可添加默認方法。即使擁有如此多方法,該接口仍是函數式接口,compare用於定義比較方式
首先定義個類,Student
package com.wzj.strategy; /** * @Author: wzj * @Date: 2020/5/6 21:15 * @Desc: */ public class Student implements Comparable<Student>{ private int age; private String name; public Student(int age, String name) { this.age = age; this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int compareTo(Student o) { return this.age - o.age; } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + '\'' + '}'; } }
定義年齡比較器
package com.wzj.strategy; import java.util.Comparator; /** * @Author: wzj * @Date: 2020/5/6 21:19 * @Desc: 年齡比較器 */ public class AgeComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.getAge() - o2.getAge(); } }
定義姓名比較器
package com.wzj.strategy; import java.util.Comparator; /** * @Author: wzj * @Date: 2020/5/6 21:19 * @Desc: 姓名比較器 */ public class NameComparator implements Comparator<Student> { @Override public int compare(Student o1, Student o2) { return o1.getName().charAt(0) - o2.getName().charAt(0); } }
測試類
package com.wzj.strategy; import java.util.Arrays; /** * @Author: wzj * @Date: 2020/5/6 21:24 * @Desc: */ public class TestComparator { public static void main(String[] args) { Student s1 = new Student(18, "zhangsan"); Student s2 = new Student(15, "lisi"); Student s3 = new Student(10,"wangwu"); Student[] students = {s1, s2, s3}; System.out.print("數組排序前:"); printArray(students); System.out.println(); Arrays.sort(students); System.out.print("數組經過Comparable接口排序後:"); printArray(students); System.out.println(); Arrays.sort(students, new AgeComparator()); System.out.print("數組經過年齡比較器AgeComparator排序後:"); printArray(students); System.out.println(); Arrays.sort(students, new NameComparator()); System.out.print("數組經過姓名比較器NameComparator排序後:"); printArray(students); } public static void printArray (Student[] students) { for (Student student : students) { System.out.print(student.toString() + ","); } } }
測試結果
數組排序前:Student{age=18, name='zhangsan'},Student{age=15, name='lisi'},Student{age=10, name='wangwu'}, 數組經過Comparable接口排序後:Student{age=10, name='wangwu'},Student{age=15, name='lisi'},Student{age=18, name='zhangsan'}, 數組經過年齡比較器AgeComparator排序後:Student{age=10, name='wangwu'},Student{age=15, name='lisi'},Student{age=18, name='zhangsan'}, 數組經過姓名比較器NameComparator排序後:Student{age=15, name='lisi'},Student{age=10, name='wangwu'},Student{age=18, name='zhangsan'},
Spring Bean 實例化,是經過InstantiationStrategy接口實現的,根據建立對象狀況的不一樣,提供了三種方法:無參構造方法、有參構造方法、工廠方法。以下
public interface InstantiationStrategy { /** * 默認構造方法 */ Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) throws BeansException; /** * 指定構造方法 */ Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, Constructor<?> ctor, @Nullable Object... args) throws BeansException; /** * 工廠方法 */ Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Object factoryBean, Method factoryMethod, @Nullable Object... args) throws BeansException; }
InstantiationStrategy 接口有兩個實現類:SimpleInstantiationStrategy 和 CglibSubclassingInstantiationStrategy。SimpleInstantiationStrategy 對以上三個方法都作了簡單的實現。
若是是工廠方法實例化,則直接使用反射建立對象,以下:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Object factoryBean, final Method factoryMethod, @Nullable Object... args) { try { if (System.getSecurityManager() != null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(factoryMethod); return null; }); } else { ReflectionUtils.makeAccessible(factoryMethod); } Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get(); try { currentlyInvokedFactoryMethod.set(factoryMethod); Object result = factoryMethod.invoke(factoryBean, args); if (result == null) { result = new NullBean(); } return result; } finally { if (priorInvokedFactoryMethod != null) { currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod); } else { currentlyInvokedFactoryMethod.remove(); } } } // 省略 catch }
若是是構造方法實例化,則是先判斷是否有 MethodOverrides,若是沒有則是直接使用反射,若是有則就須要 CGLIB 實例化對象。以下:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. if (!bd.hasMethodOverrides()) { Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { final Class<?> clazz = bd.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged( (PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor); } else { constructorToUse = clazz.getDeclaredConstructor(); } bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Throwable ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } return BeanUtils.instantiateClass(constructorToUse); } else { // Must generate CGLIB subclass. return instantiateWithMethodInjection(bd, beanName, owner); } } public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, final Constructor<?> ctor, @Nullable Object... args) { if (!bd.hasMethodOverrides()) { if (System.getSecurityManager() != null) { // use own privileged to change accessibility (when security is on) AccessController.doPrivileged((PrivilegedAction<Object>) () -> { ReflectionUtils.makeAccessible(ctor); return null; }); } return (args != null ? BeanUtils.instantiateClass(ctor, args) : BeanUtils.instantiateClass(ctor)); } else { return instantiateWithMethodInjection(bd, beanName, owner, ctor, args); } }
SimpleInstantiationStrategy 對 instantiateWithMethodInjection() 的實現任務交給了子類 CglibSubclassingInstantiationStrategy。
類 CglibSubclassingInstantiationStrategy 爲 Spring 實例化 bean 的默認實例化策略,其主要功能仍是對父類功能進行補充:其父類將 CGLIB 的實例化策略委託其實現
//SimpleInstantiationStrategy protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { throw new UnsupportedOperationException("Method Injection not supported in SimpleInstantiationStrategy"); } //CglibSubclassingInstantiationStrategy @Override protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { return instantiateWithMethodInjection(bd, beanName, owner, null); }
CglibSubclassingInstantiationStrategy 實例化 bean 策略是經過其內部類 CglibSubclassCreator 來實現的。
protected Object instantiateWithMethodInjection(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner, @Nullable Constructor<?> ctor, @Nullable Object... args) { return new CglibSubclassCreator(bd, owner).instantiate(ctor, args); }
優勢
缺點