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通过在内部包装控制范围之外的对象,把源接口转换成目标接口。适配器模式主要运用在希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。
至于其他博客所说的“类适配器模式”或者“对象适配器模式”等,可以参考:
优点
- 目标类和适配类解耦,添加一个适配器类来重用现有的适配者类,不需要改变原有的目标类和适配者类。
- 具有透明性和复用性,把所有的业务逻辑都封装到适配器类中,对于用户来说是透明的,只需要使用Target = new Adapter();适配者类主要用于对数据的操作,那么适配者类可以用在不同的系统和适配器等中复用。
- 同时增加了扩展性和灵活性
限制
- Target只能是接口(或者抽象类????)
应用举例
大话设计模式P172
3、简单工厂模式(静态工厂方法模式):
实例化出合适的对象(遵循某个接口的子类对象),通过多态,返回对象(子类对象向上转型为相应的接口)的方式。即:一个工厂类根据传入的参数动态决定应该产生哪个类的对象。
例子:用一种面向对象语言(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;
}
}
4、工厂方法设计模式:大话数据模式P69-72
接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂设计模式。工厂方法模式实现时,客户端需要决定实例化哪个工厂类(比如哪个工厂类来实现运算类),选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移动到了客户端代码来进行。上例的简单工厂方法中,你想要加功能,就需要修改operationFactory工厂类,但是在工厂方法设计模式中,你只需要单独的添加相应的Operation或者Factory子类(继承的方式),不用修改Operation和Factory类。
例程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
*///:~