Proxy
意图
为另一个对象提供代理或占位符以控制对它的访问。
适用性
-
远程代理为不同地址空间中的对象提供本地代表。
-
虚拟代理按需创建昂贵的对象。
-
保护代理控制对原始对象的访问。
-
智能引用是裸指针的替代品,它在访问对象时执行额外的操作。
后果
-
远程代理可以隐藏对象位于不同地址空间的事实。
-
虚拟代理可以执行优化,例如按需创建对象。
-
保护代理和智能引用都允许在访问对象时执行额外的内务处理任务。
static proxy
struct
demo
假设我们想在 ||
之前添加一些方法 RealSubject.operation()之后,怎么办?
- Subject.java
public interface Subject {
void operation();
}
- RealSubject.java
public class RealSubject implements Subject {
@Override
public void operation() {
System.out.println("Real do sth.");
}
}
- ProxySubject.java
public class ProxySubject implements Subject {
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void operation() {
System.out.println("before...");
subject.operation();
System.out.println("after...");
}
}
- test
public class ProxySubjectTest extends TestCase {
@Test
public void testProxy() {
Subject subject = new ProxySubject(new RealSubject());
subject.operation();
}
}
- result
before...
Real do sth.
after...
Process finished with exit code 0
dynamic proxy
为什么我们使用动态代理?
如果方法很多,很难用静态代理来解决。
struct
- Request.java
public interface Request {
void request();
void response();
}
- RealRequest.java
public class RealRequest implements Request {
@Override
public void request() {
System.out.println("Real request");
}
@Override
public void response() {
System.out.println("Real response");
}
}
- ProxyHandler.java
我们使用reflect来动态创建class文件,目标对象是灵活的。
package com.ryo.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created by 侯彬彬 on 2016/7/18.
*/
public class ProxyHandler implements InvocationHandler {
private Object target;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("dynamic before...");
Object result = method.invoke(target, args);
System.out.println("dynamic after...\n");
return result;
}
}
- test
public class DynamicProxyTest extends TestCase {
@Test
public void testProxy() {
ProxyHandler proxyHandler = new ProxyHandler();
Request request = (Request) proxyHandler.bind(new RealRequest());
request.request();
request.response();
}
}
- result
dynamic before...
Real request
dynamic after...
dynamic before...
Real response
dynamic after...
Process finished with exit code 0
Tips:可以看到,java的动态代理是依赖于 interface,如果没有接口,我们可以使用aspectj来 解决这个问题。
Strategy
意图
定义一系列算法,封装每个算法,并使它们可以互换。 策略让算法独立于使用它的客户而变化。
适用性
-
许多相关类仅在行为上有所不同。 策略提供了一种配置具有多种行为之一的类的方法。
-
你需要一个算法的不同变体。 例如,您可以定义反映不同空间/时间权衡的算法。
当这些变体被实现为算法的类层次结构时,可以使用策略 [HO87]。
-
一种算法使用了客户不应该知道的数据。 使用策略模式可以避免暴露复杂的、特定于算法的数据结构。
-
一个类定义了许多行为,这些行为在其操作中表现为多个条件语句。
将相关的条件分支移动到它们自己的 Strategy 类中,而不是许多条件。
Struct
后果
-
继承可以帮助分解出算法的通用功能。
-
将算法封装在单独的 Strategy 类中,使您可以独立于其上下文改变算法,从而更容易切换、理解和扩展。
-
策略消除了条件语句。
-
策略可以提供相同行为的不同实现。 客户可以在具有不同时间和空间权衡的策略中进行选择。
缺点
-
客户必须了解不同的策略。
-
Strategy 和 Context 之间的通信开销。
-
增加的对象数量。
实施
假设我们对不同级别的客户有不同的计数。
-
普通会员:不计
-
高级会员:0.9
-
贵宾:0.7
这是代码:
- PriceStrategy.java
public interface PriceStrategy {
double calcPrice(double price);
}
- CommonMemberStrategy.java
public class CommonMemberStrategy implements PriceStrategy {
@Override
public double calcPrice(double price) {
System.out.println("Common member has no count...");
return price;
}
}
- AdvancedMemberStrategy.java
public class AdvancedMemberStrategy implements PriceStrategy {
private static final double COUNT = 0.9;
@Override
public double calcPrice(double price) {
System.out.println("Advanced member has the count of " + COUNT);
return price * COUNT;
}
}
- VIPStrategy.java
public class VIPStrategy implements PriceStrategy {
private static final double COUNT = 0.7;
@Override
public double calcPrice(double price) {
System.out.println("VIP has the count of " + COUNT);
return price * COUNT;
}
}
- Price.java
public class Price {
private PriceStrategy priceStrategy;
public Price(PriceStrategy priceStrategy) {
this.priceStrategy = priceStrategy;
}
public double getPrice(double price) {
return priceStrategy.calcPrice(price);
}
}
- test
public class PriceTest extends TestCase {
public void testGetPrice() {
final double PRICE = 10.0;
Price price = new Price(new CommonMemberStrategy());
price.getPrice(PRICE);
Price price1 = new Price(new AdvancedMemberStrategy());
price1.getPrice(PRICE);
Price price2 = new Price(new VIPStrategy());
price2.getPrice(PRICE);
}
}
- result
Common member has no count...
Advanced member has the count of 0.9
VIP has the count of 0.7
Process finished with exit code 0