1、策略设计模式
创建一个能够根据所传递参数对象的不同而具有不同行为的方法,被称为策略设计模式。这类方法包含算法中所要执行的不变部分,而“策略”包含变化的部分。
接口的一种常见用法就是策略模式,编写一个执行某些操作的方法,而该方法将接受一个同样是你指定的接口,就可以用任何你想要的对象来调用我的方法,只要你的对象遵循我的接口。这样使你的方法更加灵活、通用,并且更具有可复用性。
a、在本例中Processor就是一个“策略”,在Main函数中把三个不同类型的策略用到了同一个String对象s上。
例程:

package interfaces;
import java.util.*;

class Processer{
    public String name(){
        return getClass().getSimpleName();
    }
    public Object process(Object object){
        return object;
    }
}
class UpCase extends Processer{
    @Override
    public Object process(Object object) {
        return ((String)object).toUpperCase();
    }
}
class DownCase extends Processer{
    @Override
    public Object process(Object object) {
        return ((String)object).toLowerCase();
    }
}
class Spliter extends Processer{
    @Override
    public Object process(Object object) {
    //创建String数组的快捷方式
        return Arrays.toString(((String)object).split(" "));
    }
}
public class Apply {
    private static String s = "Hello word I am Fine !";
    public static void process(Processer p,Object s){
        System.out.println(p.process(s));
    }
    public static void main(String[] args){
        Processer[] processer = {new UpCase(),new DownCase(),new Spliter()};
        for(Processer p:processer){
            process(p,s);
        }
    }
}
/*
OutPut
HELLO WORD I AM FINE !
hello word i am fine !
[Hello, word, I, am, Fine, !]
*/

b、Scanner类的构造器接受的就是一个Readable接口。Readable接口是单独为Scanner创建的,以使得Scanner不必将其参数限制为某个特定类。通过这种方法,Scanner可以作用于更多的类型。如果你创建了一个新的类,并且想让Scanner可以作用于它,那么就应该让它implement Readable。
例程:

//: interfaces/RandomWords.java
// Implementing an interface to conform to a method.
import java.nio.*;
import java.util.*;

public class RandomWords implements Readable {
  private static Random rand = new Random(47);
  private static final char[] capitals =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
  private static final char[] lowers =
    "abcdefghijklmnopqrstuvwxyz".toCharArray();
  private static final char[] vowels =
    "aeiou".toCharArray();
  private int count;
  public RandomWords(int count) { this.count = count; } 
  /*Readble 接口只要求实现read()方法,在read内部,将输入内容添加到CharBuffer参数中,在没有输入时返回-1;
  */
  public int read(CharBuffer cb) {
    if(count-- == 0)
      return -1; // Indicates end of input
    cb.append(capitals[rand.nextInt(capitals.length)]);
    for(int i = 0; i < 4; i++) {
      cb.append(vowels[rand.nextInt(vowels.length)]);
      cb.append(lowers[rand.nextInt(lowers.length)]);
    }
    cb.append(" ");
    return 10; // Number of characters appended
  }
  public static void main(String[] args) {
    Scanner s = new Scanner(new RandomWords(10));
    while(s.hasNext())
      System.out.println(s.next());
  }
} /* Output:
Yazeruyac
Fowenucor
Goeazimom
Raeuuacio
Nuoadesiw
Hageaikux
Ruqicibui
Numasetih
Kuuuuozog
Waqizeyoy
*///:~

2、适配器设计模式(包装器)
应用场景

系统的数据和行为都正确,但是接口不符,目的是是控制范围之外的一个原有对象与某个接口匹配,即:Adapter通过在内部包装控制范围之外的对象,把源接口转换成目标接口。适配器模式主要运用在希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。

java策略工厂泛型 java策略模式和工厂模式_ja


java策略工厂泛型 java策略模式和工厂模式_ide_02


java策略工厂泛型 java策略模式和工厂模式_java_03


至于其他博客所说的“类适配器模式”或者“对象适配器模式”等,可以参考:


优点

  • 目标类和适配类解耦,添加一个适配器类来重用现有的适配者类,不需要改变原有的目标类和适配者类。
  • 具有透明性和复用性,把所有的业务逻辑都封装到适配器类中,对于用户来说是透明的,只需要使用Target = new Adapter();适配者类主要用于对数据的操作,那么适配者类可以用在不同的系统和适配器等中复用。
  • 同时增加了扩展性和灵活性

限制

  • Target只能是接口(或者抽象类????)

应用举例

大话设计模式P172

3、简单工厂模式(静态工厂方法模式):

实例化出合适的对象(遵循某个接口的子类对象),通过多态,返回对象(子类对象向上转型为相应的接口)的方式。即:一个工厂类根据传入的参数动态决定应该产生哪个类的对象。

java策略工厂泛型 java策略模式和工厂模式_ja_04


例子:用一种面向对象语言(Java)实现一个计算机控制台程序,要求输入两个数和运算符符号,得到结果。

运算类:Operation

public class Operation {

    double numberA = 0;
    double numberB = 0;
    //两个get方法和set方法
    public double getNumberA() {
        return numberA;
    }

    public void setNumberA(double numberA) {
        this.numberA = numberA;
    }

    public double getNumberB() {
        return numberB;
    }

    public void setNumberB(double numberB) {
        this.numberB = numberB;
    }
    //getResult方法
    public double getResult() {
        double result = 0d;
        return result;
    }
}

简单工厂模式类(静态工厂方法模式类):

public class OperationFactory {
    public static Operation createOperate(String operate) {
        Operation oper = null;
        switch (operate) {
        case "+":
            // 向上转型
            oper = new OperationAdd();
            break;
        case "-":
            oper = new OperationSub();
            break;
        case "*":
            oper = new OperationMul();
            break;
        case "/":
            oper = new OperationDiv();
            break;
        default:
            break;
        }
        return oper;
    }
}

四个运算类:

public class OperationMul extends Operation {  
    @Override  
    public double getResult() {  
        double result = getNumberA() * getNumberB();  
        return result;  
    }  
}  

public class OperationAdd extends Operation {  
    @Override  
    public double getResult() {  
        // 假如某一天公司老板要求在乘法增加一个开根号,即可只需要改动这里  
        // double result = Math.sqrt(getNumberA() + getNumberB());  
        double result = getNumberA() + getNumberB();  
        return result;  
    }  
} 

public class OperationSub extends Operation {  
    @Override  
    public double getResult() {  
        double result = getNumberA() - getNumberB();  
        return result;  
    }  
} 

public class OperationDiv extends Operation {  
    @Override  
    public double getResult() {  
        double result = 0d;  
        if (getNumberB() != 0) {  
            result = getNumberA() / getNumberB();  
        } else {  
            try {  
                throw new Exception("除数不能为0");  
            } catch (Exception e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
            // System.out.println("除数不能为0!");  
            // System.out.println("以下结果是错误的!");  
        }  
        return result;  
    }  
}

java策略工厂泛型 java策略模式和工厂模式_ide_05


4、工厂方法设计模式:大话数据模式P69-72

接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂设计模式。工厂方法模式实现时,客户端需要决定实例化哪个工厂类(比如哪个工厂类来实现运算类),选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移动到了客户端代码来进行。上例的简单工厂方法中,你想要加功能,就需要修改operationFactory工厂类,但是在工厂方法设计模式中,你只需要单独的添加相应的Operation或者Factory子类(继承的方式),不用修改Operation和Factory类。

java策略工厂泛型 java策略模式和工厂模式_java_06

java策略工厂泛型 java策略模式和工厂模式_ja_07


例程1:把上例中的计算器改为工厂方法模式

//运算类和上例一样,没有改变;
//先构造一个工厂接口;
interface Factory {
    public Operation generateOperation();
}
//然后加减乘除各建一个具体的工厂去实现Factory接口;
class AddFactory implement Factory {
    public Operation generateOperation() {
        return new OperationAdd();
    }
}
class SubFactory implement Factory {
    public Operation generateOperation() {
        return new OperationSub();
    }
}
class MulFactory implement Factory {
    public Opration generateOperation() {
        return new OperatrionMul();
    }
}
class DivFactory implement Factory {
    public Opration generateOperation() {
        return new OperatrionMul();
    }
}

客户端的实现:

//在客户端进行选择逻辑判断
Factory operFactory = new AddFactory();
Operation Oper = operFactory.generateOperation();
oper.NumberA = 1;
oper.NumberB = 2;
double result = Oper.GetResult();

例程2:本例中就是生成遵循Game接口的导出类对象(Checkers和Chess对象)的典型方式。这与直接调用构造器不同,我们在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现对象。在本例中如果Games类表示一段复杂的代码,那么这种工厂设计模式就允许你在不同类型的游戏中复用这段代码。

interface Game { boolean move(); }
interface GameFactory { Game getGame(); }

class Checkers implements Game {
  private int moves = 0;
  private static final int MOVES = 3;
  public boolean move() {
    print("Checkers move " + moves);
    return ++moves != MOVES;
  }
}

class CheckersFactory implements GameFactory {
  public Game getGame() { return new Checkers(); }
}   

class Chess implements Game {
  private int moves = 0;
  private static final int MOVES = 4;
  public boolean move() {
    print("Chess move " + moves);
    return ++moves != MOVES;
  }
}

class ChessFactory implements GameFactory {
  public Game getGame() { return new Chess(); }
}   

public class Games {
  public static void playGame(GameFactory factory) {
    Game s = factory.getGame();
    while(s.move())
      ;
  }
  public static void main(String[] args) {
    playGame(new CheckersFactory());
    playGame(new ChessFactory());
  }
} /* Output:
Checkers move 0
Checkers move 1
Checkers move 2
Chess move 0
Chess move 1
Chess move 2
Chess move 3
*///:~

4、动态代理模式
动态代理的详细讲解请参考:
例子可参考(java编程思想P415):

package generics;//: generics/DynamicProxyMixin.java
import utils.TwoTuple;

import java.lang.reflect.*;
import java.util.*;

import static utils.Tuple.tuple;

class MixinProxy implements InvocationHandler {
  //需要被代理的真实对象
  Map<String,Object> delegatesByMethod;
  //给我们要代理的真是对象赋初值
  public MixinProxy(TwoTuple<Object,Class<?>>... pairs) {
    delegatesByMethod = new HashMap<String,Object>();
    for(TwoTuple<Object,Class<?>> pair : pairs) {
      for(Method method : pair.second.getMethods()) {
        String methodName = method.getName();
        // The first interface in the map
        // implements the method.
        if (!delegatesByMethod.containsKey(methodName))
          delegatesByMethod.put(methodName, pair.first);
      }
    }
  }
  //通过代理对象调用一个method时,该method的调用会被转发给invoke方法来进行调用。
  public Object invoke(Object proxy, Method method,
    Object[] args) throws Throwable {
    String methodName = method.getName();
    Object delegate = delegatesByMethod.get(methodName);
    return method.invoke(delegate, args);
  }
  //通过Proxy的newProxyInstance来创建我们的代理对象,
  //第一个参数:通过cl的ClassLoader对象来加载我们的代理对象
  //第二个参数:表示要代理的真实对象的接口,这样儿就能调用这组接口中的真实方法了
  //第三个参数:将该代理对象关联到上方的InvocationHandler这个对象上。

  @SuppressWarnings("unchecked")
  public static Object newInstance(TwoTuple... pairs) {
    Class[] interfaces = new Class[pairs.length];
    for(int i = 0; i < pairs.length; i++) {
      interfaces[i] = (Class)pairs[i].second;
    }
    ClassLoader cl =
      pairs[0].first.getClass().getClassLoader();
    return Proxy.newProxyInstance(
      cl, interfaces, new MixinProxy(pairs));
  }
}   

public class DynamicProxyMixin {
  public static void main(String[] args) {
    //创建代理对象mixin来代理Basic、TimeStamped和SerialNumbered接口(或者类)
    // 对应的BasicImp、TimeStampedImp和SerialNumberedImp这三个对象;
    // 同时将代理对象mixin关联到 InvocationHandler对象上。
    Object mixin = MixinProxy.newInstance(
      tuple(new BasicImp(), Basic.class),
      tuple(new TimeStampedImp(), TimeStamped.class),
      tuple(new SerialNumberedImp(),SerialNumbered.class));
    //在调用相应的method之前,需要将代理对象强制转型为恰当的类型。由于在newProxyInstance这个方法中,
    //我们给代理对象提供了一组接口,因此可以将该代理对象强制类型转化为这组接口中的任意一个。
    Basic b = (Basic)mixin;
    TimeStamped t = (TimeStamped)mixin;
    SerialNumbered s = (SerialNumbered)mixin;
    b.set("Hello");
    System.out.println(b.get());
    System.out.println(t.getStamp());
    System.out.println(s.getSerialNumber());
  }
} /* Output: (Sample)
Hello
1132519137015
1
*///:~