1 動態代理
代理是什麼?
代理其實就是代爲處理的意思,個人理解就是產生一個處理類對需要代理的對象進行處理,並且返回該代理對象
靜態代理
首先實現一個Moveable接口,表示代理與被代理的對象都屬於同一個類別
public interface Moveable {
void move();
void stop();
}
接下來實現一個被代理對象坦克類,有着坦克開始與結束的方法
public class Tank implements Moveable{
@Override
public void move() {
System.out.println("Tank moving 。。");
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
System.out.println("Tank stop");
}
}
接下來如果想要知道Tank的move方法允許了多久的話,最直接的就是使用繼承方法,但是如果使用繼承的話,想要再知道運行的日誌的話就需要再繼承擴展一個類,因此使用聚合來解耦合。
實現時間代理
public class TankTimeProxy implements Moveable{
Moveable t;
public TankTimeProxy(Moveable t) {
super();
this.t = t;
}
@Override
public void move() {
Long start = System.currentTimeMillis();
t.move();
long end = System.currentTimeMillis();
System.out.println(end-start);
}
@Override
public void stop() {
Long start = System.currentTimeMillis();
t.stop();
long end = System.currentTimeMillis();
System.out.println(end-start);
}
}
實現日誌代理
public class TankLogProxy implements Moveable{
Moveable t;
public TankLogProxy(Moveable t) {
super();
this.t = t;
}
@Override
public void move() {
System.out.println("Tank start");
t.move(); //這裏調用的其實是Tank的方法
long end = System.currentTimeMillis();
System.out.println("Tank end");
}
@Override
public void stop() {
}
}
調用地方的代碼如下
public static void main(String[] args) throws NoSuchMethodException, IOException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
Tank t =new Tank();
TankTimeProxy ttp =new TankTimeProxy(t);
TankLogProxy tlp = new TankLogProxy(ttp); //在時間代理上再加上日誌代理
// Moveable m = tlp;
Moveable m = tlp;
m.move();
}
打印數據的數據如下
Tank start
Tank moving 。。
861
Tank end
動態代理
(這裏借用網上的例子,代碼已經測過無誤)
在完成了靜態代理之後,我們需要考慮另外的問題,如果在我們需要計算的是除了move之外的其他方法的運行時間,那麼豈不是又要生成一個代理類了?多個方法的話就是多個代理類,會導致類無限制擴展。因此就用到了動態代理
使用動態代理需要用到反射,反射是用於獲取已創建實例的方法或者屬性,並對其進行調用或者賦值。在這裏我們可以動態一個代理對象,並且動態編譯。然後,再通過反射創建對象並加載到內存中,就實現了對任意對象進行代理
第一步:定義自己的一個代理的邏輯處理接口,用來實現處理自定義邏輯
public interface InvocationHandler {
void invoke(Object o, Method m) throws InvocationTargetException, IllegalAccessException;
}
第二步:定義一個運行時間處理器,用來處理代理對象,
public class TimeHandler implements InvocationHandler {
//被代理的對象
private Object target;
public TimeHandler(Object target) {
this.target = target;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
// o 是代理對象
@Override
public void invoke(Object o, Method m) throws InvocationTargetException, IllegalAccessException {
long start = System.currentTimeMillis();
System.out.println("starttiem: "+ start);
m.invoke(target); //調用被代理對象原來的方法
long end = System.currentTimeMillis();
System.out.println("time: " + (end -start));
}
}
第三步:編寫動態代理的代碼:
public class Proxy {
/**
* 動態代理
* 產生新的代理類
* infce 產生對應接口的代理 該接口對應的處理方法
* @return
*/
public static Object newProxyInstance(Class infce, InvocationHandler h) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
String methodStr = "";
Method[] methods = infce.getMethods();
String rt = "\r\n";
for(Method m : methods) { //動態代碼 編譯後動態生成一個對象,該對象包含着InvocationHandler,
methodStr += "@Override" + rt +
"public void " + m.getName() + "() {" + rt +
" try {" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt + //傳入的是this
" }catch(Exception e) {e.printStackTrace();}" + rt +
"}";
}
String src =
"package com.bjsxt.proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy1 implements " + infce.getName() + "{" + rt +
" public $Proxy1(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" com.bjsxt.proxy.InvocationHandler h;" + rt +
methodStr +
"}";
String fileName =
"d:/src/com/bjsxt/proxy/$Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);//將要編譯的代碼寫到文件中去
fw.flush();
fw.close();
//編譯TimeProxy源碼
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
//加載到內存中並創建對象
URL[] urls = new URL[] {new URL("file:/" + "d:/src/")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1");
System.out.println(c);
//傳過來那個處理器就按照那個處理器去實現
Constructor ctr = c.getConstructor(InvocationHandler.class);
Object m = ctr.newInstance(h);
//m.move();
return m;
}
}
第四步:調用:
public static void main(String[] args) throws Exception {
Tank t = new Tank();
InvocationHandler h = new TimeHandler(t);
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);
m.move();
}
在這裏Proxy.newProxyInstance(Moveable.class, h)生成的Proxy1代理類爲:
class Prox1 implements Moveable {
private InvocationHandler handler;
public TimeProxy(InvocationHandler handler) {
this.handler = handler;
}
@Override
public void move() {
try {
Method method = com.youngfeng.proxy.Flyable.class.getMethod("move");
this.handler.invoke(this, method, null);
} catch(Exception e) {
e.printStackTrace();
}
}
}
方法調用鏈:Proxy1 . move() -> TimeHandler.invoke(Object o, Method m) -> Tank.move();
主要邏輯
- Proxy->newProxyInstance(infs, handler) 用於生成代理對象
- InvocationHandler:這個接口主要用於自定義代理邏輯處理
- 爲了完成對被代理對象的方法攔截,我們需要在InvocationHandler對象中傳入被代理對象實例。
因此對其他對象進行代理就不再需要修改newProxyInstance方法中的代碼
2 策略模式
策略模式主要用於不同的類根據不同的方法去解決,比如一隻貓的屬性有體重跟身高,實現按身高進行排序與按體重進行排序,即可使用策略模式
- Comparable表明實現該接口的類必須實現compare方法,
- Comparator則是比較器的具體實現
第一步:定義一個實現了Comparable的Cat類
public class Cat implements Comparable{
int Height;
int weight;
Comparator comparator;
public int getHeight() {
return Height;
}
public void setHeight(int height) {
Height = height;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public Comparator getComparator() {
return comparator;
}
public void setComparator(Comparator comparator) {
this.comparator = comparator;
}
@Override
public int compareTo(Object o) {
return comparator.compare(this, o);
}
}
在這個類裏面實現了一個繼承器,傳入自己實現的Comparator可以實現對身高和體重進行比較。
第二步:實現一個接口類使它的實現類確定實現了compareTo方法
public interface Comparable {
int compareTo(Object o);
}
第三步:實現一個比較器的接口:
public interface Comparator {
int compare(Object o1, Object o2);
}
第四步:繼承Comparator接口實現身高比較器
public class CatHeightComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
Cat c1 = (Cat)o1;
Cat c2 = (Cat)o2;
if (c1.getHeight() > c2.getHeight()) return 1;
else if (c1.getHeight() > c2.getHeight()) return -1;
return 0;
}
}
策略模式其實就是需要變化的類其中聚合一個策略,根據需要傳入不同的實現類實現不同的需要
3 狀態模式
狀態模式使用對象的形式來記錄某種狀態。使用狀態模式可以省去多個if-else或者是switch的判斷。可以直接使用對象方法的形式來處理邏輯。
例如在這裏實現兩個類Boy和MM類,其中MM中包含了抽象類State。代表了MM此時的心情
public class Boy {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class MM {
private MMState state = new MMHappyState();
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void smile(){
state.smile();
}
public void cry(){
state.cry();
}
public void say(){
state.say();
}
}
抽象類MyState
public abstract class MMState {
public abstract void smile();
public abstract void cry();
public abstract void say();
}
代表MM好心情的MMHappyState
public class MMHappyState extends MMState{
@Override
public void smile() {
}
@Override
public void cry() {
}
@Override
public void say() {
}
}
因此當MM狀態改變時,比如從開心的哭變成悲傷的哭只需要改變State即可,不需要修改其他代碼。
4 工廠模式
抽象工廠
當需要新的工廠時直接繼承VehicleFactory就可以
第一步:Moveable接口
public interface Moveable {
void run();
}
所有的交通工具都實現了該接口
第二步:定義了汽車和飛機類
public class Plane implements Moveable{
@Override
public void run() {
System.out.println("plane");
}
}
public class Car implements Moveable{
private static Car c = new Car();
public void run(){
System.out.println("run");
}
//靜態工廠方法 用來產生car產品
public static Car getInstance(){
return c;
}
}
第三步:實現一個工廠類,負責實現創建所有實例的內部邏輯。
public abstract class VehicleFactory {
abstract Moveable create();
}
第四步: 實現工廠接口
public class PlaneFactory extends VehicleFactory{
@Override
Moveable create() {
return new Plane();
}
}
public class CarFactory extends VehicleFactory{
@Override
Moveable create() {
return new Car();
}
}
在調用時需要那個類的工廠直接new它的工廠就行
public static void main(String[] args) {
VehicleFactory factory = new PlaneFactory();
Moveable m = factory.create();
m.run();
}
5 責任鏈模式
使多個對象都有處理請求的機會,從而避免了請求的發送者和接收者之間的耦合關係。將這些對象串成一條鏈,並沿着這條鏈一直傳遞該請求,直到有對象處理它爲止。
目標
用Filter模擬處理Request、Response
思路技巧
(1)Filter的doFilter方法改爲doFilter(Request,Resopnse,FilterChain),有FilterChain引用,爲利用FilterChain調用下一個Filter做準備
(2)FilterChain繼承Filter,這樣,FilterChain既是FilterChain又是Filter,那麼FilterChain就可以調用Filter的方法doFilter(Request,Resopnse,FilterChain)
(3)FilterChain的doFilter(Request,Resopnse,FilterChain)中,有index標記了執行到第幾個Filter,當所有Filter執行完後request處理後,就會return,以倒序繼續執行response處理
代碼如下:
Filter.java
public interface Filter {
void doFilter (Request request, Response response,FilterChain filterChain);
}
HTMLFilter.java :替換HTML代碼
public class HTMLFilter implements Filter {
@Override
public void doFilter(Request request, Response response,
FilterChain filterChain) {
request.setRequestStr(request.getRequestStr().replace('<', '[').replace(">", "]")+"---HTMLFilter()");
filterChain.doFilter(request, response, filterChain);
response.setResponseStr(response.getResponseStr()+"---HTMLFilter()");
}
}
3.SensitiveFilter.java 替換敏感詞彙
public class SensitiveFilter implements Filter {
@Override
public void doFilter(Request request, Response response,
FilterChain filterChain) {
request.setRequestStr(request.getRequestStr().replace("敏感", "幸福")+"---SensitiveFilter()");
filterChain.doFilter(request, response, filterChain);
response.setResponseStr(response.getResponseStr()+"---SensitiveFilter()");
}
}
4.FilterChian.java 過濾器鏈
public class FilterChain implements Filter {
private List<Filter> filters = new ArrayList<Filter>();
int index = 0; //標記執行到第幾個filter
//把函數的返回值設爲FilterChain,返回this,就能方便鏈式編寫代碼
public FilterChain addFilter(Filter filter) {
filters.add(filter);
return this;
}
public void doFilter(Request request, Response response, FilterChain fc) {
if(index == filters.size()) return ;
Filter f = filters.get(index);
index++;
f.doFilter(request, response, fc);
}
}
5.Request.java 和 Response.java
public class Request {
private String requestStr;
public String getRequestStr() {
return requestStr;
}
public void setRequestStr(String requestStr) {
this.requestStr = requestStr;
}
}
public class Response {
private String responseStr;
public String getResponseStr() {
return responseStr;
}
public void setResponseStr(String responseStr) {
this.responseStr = responseStr;
}
}
6Test.java
public class Test {
@org.junit.Test
public void testFilter(){
String msg = "<html>敏感字眼</html>";
Request request = new Request();
request.setRequestStr(msg);
Response response = new Response();
response.setResponseStr("response------------");
FilterChain fc = new FilterChain();
fc.addFilter(new HTMLFilter()).addFilter(new SensitiveFilter());
fc.doFilter(request, response, fc);
System.out.println(request.getRequestStr());
System.out.println(response.getResponseStr());
}
}
6 命令模式
命令也是類,將命令作爲一個類來保存,當要使用的時候可以直接拿來使用
1.Client.java
public class Client {
public void request(Server server){
server.addCommand(new TextCommand());
server.addCommand(new ImageCommand());
server.doSomething();
}
}
2.Server.java
public class Server {
private List<Command> commands = new ArrayList<Command>();
public void doSomething() {
for(Command c : commands){
c.execute();
}
}
public void addCommand(Command command) {
commands.add(command);
}
}
3.Command.java
public abstract class Command {
public abstract void execute();
public abstract void unDo();
}
4.TextCommand.java
public class TextCommand extends Command {
@Override
public void execute() {
System.out.println("TextCommand...........");
}
@Override
public void unDo() {
// 涉及到操作的歷史記錄
}
}
5.ImageCommand.java
public class ImageCommand extends Command {
@Override
public void execute() {
System.out.println("ImageCommand...........");
}
@Override
public void unDo() {
// 涉及到操作的歷史記錄
}
}
6.Test.java
public class Test {
@org.junit.Test
public void test(){
Client c = new Client();
c.request(new Server());
}
}
7 橋接模式
設想如果要繪製矩形、圓形、橢圓、正方形,我們至少需要4個形狀類,但是如果繪製的圖形需要具有不同的顏色,如紅色、綠色、藍色等,此時至少有如下兩種設計方案:
• 第一種設計方案是爲每一種形狀都提供一套各種顏色的版本。
• 第二種設計方案是根據實際需要對形狀和顏色進行組合。
模式定義
橋接模式(Bridge Pattern):將抽象部分與它的實現部分分離,使它們都可以獨立地變化。它是一種對象結構型模式,又稱爲柄體(Handle and Body)模式或接口(Interface)模式
應用情況:(1)兩個維度擴展(2)排列組合
1.Gift.java 禮物
public class Gift {
GiftImpl impl;
}
2.GiftImpl.java 繼承該類是具體物品
public class GiftImpl {
}
3.WarmGift.java
public class WarmGift extends Gift {
public WarmGift(GiftImpl giftImpl) {
//調用父類的giftImpl
this.giftImpl = giftImpl;
}
@Override
public String toString() {
return this.getClass().getName()+"-----"+giftImpl.getClass().getName();
}
}
4.WildGift.java
public class WildGift extends Gift {
public WildGift(GiftImpl giftImpl) {
//調用父類的giftImpl
this.giftImpl = giftImpl;
}
@Override
public String toString() {
return this.getClass().getName()+"-----"+giftImpl.getClass().getName();
}
}
5.Flower.java
public class Folwer extends GiftImpl{
}
6.Ring.java
public class Ring extends GiftImpl{
}
7.MM.java
public class MM {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
8.Boy.java
pursue(MM mm)是送給女孩子禮物的方法 想要送不同的禮物修改gift = new WildGift(new Flower())即可
public class Boy {
private String name;
public void pursue(MM mm){
Gift gift = new WildGift(new Flower());
give(gift, mm);
System.out.println(gift);
}
public void give(Gift gift, MM mm) {
}
}
9.Test.java
public class Test {
@org.junit.Test
public void test() {
Boy b = new Boy();
b.pursue(new MM());
}
}