二十三种设计模式详解

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());
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值