Java_你应该知道的26种设计模式

四。 模板方法模式 Definition: Define the skeleton of an algorithm in an operation, defe

四。 模板方法模式

Definition: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. 

Templet Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

它包含一个抽象模板和一些具体的模板。

抽象模板中包含两类方法:

  • 基本方法
    • 也叫基本操作,是有抽象模板给出抽象接口,子类给出实现的方法,并且这些方法会在模板方法中被调用;
    • 基本方法尽量设计为protected类型,符合迪米特法则
  • 模板方法
    • 可以有一个或几个,一般是一个具体方法,实现对基本方法的调度,完成固定的逻辑。
    • 为了防止恶意的操作,,一般模板方法都会加上final关键字,不允许被覆写。

Demo Coding:

package com.model;

public abstract class HummerModel {
    /**
     * 首先,这个模型要能发动起来,不管是电力发动还是手摇发动
     * 所以具体是怎么发动就要根据不同的型号自己实现发动的方法
     */
    public abstract void start();
    
    /**
     * 不仅能够发动,还要能够停止
     */
    public abstract void stop();
    
    /**
     * 按喇叭会响
     */
    public abstract void alarm();
    
    /**
     * 发动引擎时有隆隆声
     */
    public abstract void engineBoom();
    
    public void run() {
        this.start();
        this.engineBoom();
        this.alarm();
        this.stop();
    }    
}



package com.model;

public class HummerH1Model extends HummerModel {

    @Override
    public void start() {
        // TODO Auto-generated method stub
        System.out.println("H1型号是这样启动的.....");
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub
        System.out.println("H1型号是这样停止的.....");
    }

    @Override
    public void alarm() {
        // TODO Auto-generated method stub
        System.out.println("H1型号是这样鸣笛的......");
    }

    @Override
    public void engineBoom() {
        // TODO Auto-generated method stub
        System.out.println("H1型号是这样发动引擎的......");
    }

}




package com.model;

public class HummerH2Model extends HummerModel {

    @Override
    public void start() {
        // TODO Auto-generated method stub
        System.out.println("H2型号是这样启动的......");
    }

    @Override
    public void stop() {
        // TODO Auto-generated method stub
        System.out.println("H2型号是这样停止的......");
    }

    @Override
    public void alarm() {
        // TODO Auto-generated method stub
        System.out.println("H2型号是这样鸣笛的......");
    }

    @Override
    public void engineBoom() {
        // TODO Auto-generated method stub
        System.out.println("H2型号是这样发动引擎的......");
    }

}



package com.model;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //某公司要H1模型的悍马汽车
        HummerModel hm = new HummerH1Model();
        //H1模型演示如下
        hm.run();
    }

}
View Code

 

 

五。 建造者模式(Builder Pattern)

Definition: Separate the construction of a complex object from its representation so that the same

construction process can create different representations.

在一般的建造者模式中,有如下4个角色:

  • 产品类(实际就是上面的第四种模板方法模式的实现)
    • 通常是实现了模板方法模式,也就是有模板方法和基本方法;
  • 抽象建造者Builder
    • 规范产品的组建,一般由子类实现。
  • 具体构建着ConcreteBuilder
    • 实现抽象建造者的所有方法,并且返回一个组建好的对象
  • 导演类
    • 负责根据客户的需要安排已有模块的顺序,然后告诉Builder开始建造,然后获得ConcreteBuilder返回的对象,最后呈现给客户

所以说,不论是经由模板模式构建的产品类还是抽象或具体的建造者,对于客户都是屏蔽的,客户只需要将他的具体需求告诉导演类,最终由导演类统筹安排,将结果返回给客户。

建造者模式的使用场景有:

  • 如果需求是:相同的方法,不同的执行顺序,产生不同的事件结果时,可以考虑使用。
  • 一个对象由多个零件或部件构成,,但是运行产生的结果又不相同;
  • 所以,,建造者模式关注的是零件类型装配顺序不同!!!这是他与工厂方法最大的不同!!
  • 工厂模式的重点则是创建,创建零件的它的主要职责,组装顺序是它不care的!!

Demo Coding:

/*-------------------------模板方法模式的实现-----------------------------*/
package com.builderPattern;

import java.util.ArrayList;

public abstract class CarModel {
    //这个参数是各个基本方法执行的顺序
    private ArrayList<String> sequence = new ArrayList<String>();
    
    
    protected abstract void start();
    
    protected abstract void stop();
    
    protected abstract void alarm();
    
    protected abstract void engineBoom();
    
    final public void run() {
        //循环一遍sequence,谁在前就限制性谁
        for(int i=0; i<this.sequence.size(); i++) {
            String actionName = this.sequence.get(i);
            if(actionName.equalsIgnoreCase("start"))
                this.start();
            else if(actionName.equalsIgnoreCase("stop"))
                this.stop();
            else if(actionName.equalsIgnoreCase("alarm"))
                this.alarm();
            else if(actionName.equalsIgnoreCase("engine boom"))
                this.engineBoom();
        }
    }
    
    
    final public void setSequence(ArrayList<String> sequence) {
        this.sequence = sequence;
    }
    
    
}

package com.builderPattern;

public class BenzModel extends CarModel {

    @Override
    protected void start() {
        // TODO Auto-generated method stub
        System.out.println("奔驰是这样run....");
    }

    @Override
    protected void stop() {
        // TODO Auto-generated method stub
        System.out.println("奔驰是这样stop....");
    }

    @Override
    protected void alarm() {
        // TODO Auto-generated method stub
        System.out.println("奔驰是这样alarm....");
    }

    @Override
    protected void engineBoom() {
        // TODO Auto-generated method stub
        System.out.println("奔驰是这样engine boom.....");
    }

}


package com.builderPattern;

public class BMWModel extends CarModel {

    @Override
    protected void start() {
        // TODO Auto-generated method stub
        System.out.println("宝马是这样start....");
    }

    @Override
    protected void stop() {
        // TODO Auto-generated method stub
        System.out.println("宝马是这样stop....");
    }

    @Override
    protected void alarm() {
        // TODO Auto-generated method stub
        System.out.println("宝马是这样alarm....");
    }

    @Override
    protected void engineBoom() {
        // TODO Auto-generated method stub
        System.out.println("宝马是这样engine boom....");
    }

}

/*-------------------------抽象建造者-----------------------------*/
package com.builderPattern;

import java.util.ArrayList;

public abstract class CarBuilder {
    //建造一个模型,你要给我一个顺序,就是组装顺序
    public abstract void setSequence(ArrayList<String> sequence);
    
    //设置完顺序后,既可以直接拿到这个车辆模型
    public abstract CarModel getCarModel();
}

/*--------------具体建造者的实现,返回一个具体的model------------------------*/
package com.builderPattern;

import java.util.ArrayList;

public class BenzBuilder extends CarBuilder {
    private BenzModel benz = new BenzModel();

    @Override
    public void setSequence(ArrayList<String> sequence) {
        // TODO Auto-generated method stub
        this.benz.setSequence(sequence);
    }

    @Override
    public CarModel getCarModel() {
        // TODO Auto-generated method stub
        return this.benz;
    }

}


package com.builderPattern;

import java.util.ArrayList;

public class BMWBuilder extends CarBuilder {
    private BMWModel bmw = new BMWModel();
    
    
    @Override
    public void setSequence(ArrayList<String> sequence) {
        // TODO Auto-generated method stub
        this.bmw.setSequence(sequence);
    }

    @Override
    public CarModel getCarModel() {
        // TODO Auto-generated method stub
        return this.bmw;
    }

}

/*-------------------------导演类的实现,实现客户的需求-------------------------*/
package com.builderPattern;

import java.util.ArrayList;

public class Director {
    private ArrayList<String> sequence = new ArrayList<String>();
    private BenzBuilder benzBuilder = new BenzBuilder();
    private BMWBuilder bmwBuilder = new BMWBuilder();
    
    /**
     * 获得A类型的奔驰汽车
     * @return
     */
    public BenzModel getABenzModel() {
        this.sequence.clear();
        
        this.sequence.add("start");
        this.sequence.add("stop");
        this.benzBuilder.setSequence(sequence);
        return (BenzModel) this.benzBuilder.getCarModel();
    }
    
    /**
     * 获得B类型的奔驰汽车
     * @return
     */
    public BenzModel getBBenzModel() {
        this.sequence.clear();
        
        this.sequence.add("engine boom");
        this.sequence.add("start");
        this.sequence.add("stop");
        this.benzBuilder.setSequence(sequence);
        return (BenzModel) this.benzBuilder.getCarModel();
    }
    
    /**
     * 获得A类型的宝马车型
     * @return
     */
    public BMWModel getABMWModel() {
        this.sequence.clear();
        
        this.sequence.add("alarm");
        this.sequence.add("start");
        this.sequence.add("stop");
        
        this.bmwBuilder.setSequence(sequence);
        return (BMWModel) this.bmwBuilder.getCarModel();
        
    }
    
    /**
     * 获得B类型的宝马车型
     * @return
     */
    public BMWModel getBBMWModel() {
        this.sequence.clear();
        
        this.sequence.add("start");
        
        this.bmwBuilder.setSequence(sequence);
        return (BMWModel) this.bmwBuilder.getCarModel();
        
    }
    
}


package com.builderPattern;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Director director = new Director();
        //制造100台A类型的奔驰
        for(int i=0; i<1000; i++) 
            director.getABenzModel().run();
        for(int i=0; i<2000; i++)
            director.getBBMWModel().run();
    }
        
}
View Code

 

 

六。代理模式(Proxy Pattern)

Definition: Provide a surrogate or placeholder for another object to control access to it.

在代理模式中,有三个角色的定义:

  • Subject抽象主题角色
    • 抽象主题可以是抽象类也可以是接口,是一个最普通的业务类型定义;
  • RealSubject具体主题角色
    • 也叫作被委托角色。是具体业务逻辑的具体执行者;
  • Proxy代理主题角色
    • 也叫委托类、代理类,它负责对真实角色的应用,把所有抽象主题类定义的方法委托给真实主题角色实现,并且在真实主题角色处理完毕后做预处理和善后工作;
  • RealSubject 和 Proxy都继承自Subject

Demo Coding:

package com.proxyPattern;

public interface IGamePlayer {
    //玩家登陆
    public void login(String name, String password);
    
    //打boss
    public void killBoss();
    
    //升级
    public void upgrade();
    
    
}


package com.proxyPattern;

public class GamePlayer implements IGamePlayer {
    private String name = "";
    
    public GamePlayer(String name) {
        this.name = name;
    }
    
    @Override
    public void login(String name, String password) {
        // TODO Auto-generated method stub
        System.out.println("Congradulation! " + this.name + " logined in.");
    }

    @Override
    public void killBoss() {
        // TODO Auto-generated method stub
        System.out.println(this.name + " is killing his boss..");
    }

    @Override
    public void upgrade() {
        // TODO Auto-generated method stub
        System.out.println(this.name + " uograded 1.");
    }

}


package com.proxyPattern;

public class GamePlayerProxy implements IGamePlayer {
    IGamePlayer gamePlayer = null;
    
    public GamePlayerProxy(IGamePlayer gamePlayer) {
        this.gamePlayer = gamePlayer;
    }
    
    
    @Override
    public void login(String name, String password) {
        // TODO Auto-generated method stub
        this.gamePlayer.login(name, password);
    }

    @Override
    public void killBoss() {
        // TODO Auto-generated method stub
        this.gamePlayer.killBoss();
    }

    @Override
    public void upgrade() {
        // TODO Auto-generated method stub
        this.gamePlayer.upgrade();
    }

}


package com.proxyPattern;

public class Client {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        IGamePlayer gamePlayer = new GamePlayer("Tom");
        IGamePlayer proxy = new GamePlayerProxy(gamePlayer);
        proxy.login("Tom", "123");
        proxy.killBoss();
        proxy.upgrade(); 
        
        //Another player
        IGamePlayer gamePlayer2 = new GamePlayer("Jack");
        IGamePlayer proxy2 = new GamePlayerProxy(gamePlayer2);
        proxy2.login("Jack", "456");
        proxy2.killBoss();
        proxy2.upgrade(); 
        
    }

}
View Code

 

 

代理模式的扩展:

(一)普通代理

  • 要求客户端只能访问代理角色,而不能访问真实角色

(二)强制代理

  • 不管是通过代理类还是通过直接new一个主题角色类,都不能访问,只有通过真实角色指定的代理类才可以访问
  • Demo Coding:
  • package com.forceProxyPattern;
    
    public interface IGamePlayer {
        //玩家登陆
        public void login(String name, String password);
        
        //打boss
        public void killBoss();
        
        //升级
        public void upgrade();
        
        //每个人都有自己的代理
        public IGamePlayer getProxy();
    }
    
    
    package com.forceProxyPattern;
    
    public class GamePlayer implements IGamePlayer {
        private String name = "";
        //我的代理
        private IGamePlayer proxy = null;
        
        public GamePlayer(String name) {
            this.name = name;
        }
        
        @Override
        public void login(String name, String password) {
            // TODO Auto-generated method stub
            if(this.isProxy()) {
                System.out.println(this.name + " 登陆成功!");
            } else {
                System.out.println("请使用指定的代理访问");
            }
        }
    
        @Override
        public void killBoss() {
            // TODO Auto-generated method stub
            if(this.isProxy()) {
                System.out.println(this.name + " 在打怪。");
            } else {
                System.out.println("请使用指定的代理访问");
            }
        }
    
        private boolean isProxy() {
            // TODO Auto-generated method stub
            if(proxy == null)
                return false;
            else 
                return true;
        }
    
        @Override
        public void upgrade() {
            // TODO Auto-generated method stub
            if(this.isProxy()) {
                System.out.println(this.name + " 又升一级!");
            } else {
                System.out.println("请使用指定的代理访问");
            }
        }
        
        //找到自己的代理
        @Override
        public IGamePlayer getProxy() {
            // TODO Auto-generated method stub
            this.proxy = new GamePlayerProxy(this);
            return this.proxy;
        }
    
    }
    
    
    package com.forceProxyPattern;
    
    public class GamePlayerProxy implements IGamePlayer {
        private IGamePlayer gamePlayer = null;
        
        public GamePlayerProxy(IGamePlayer gamePlayer) {
            this.gamePlayer = gamePlayer;
        }
        
        
        @Override
        public void login(String name, String password) {
            // TODO Auto-generated method stub
            this.gamePlayer.login(name, password);
        }
    
        @Override
        public void killBoss() {
            // TODO Auto-generated method stub
            this.gamePlayer.killBoss();
        }
    
        @Override
        public void upgrade() {
            // TODO Auto-generated method stub
            this.gamePlayer.upgrade();
        }
    
        @Override
        public IGamePlayer getProxy() {
            // TODO Auto-generated method stub
            return this;
        }
    
    }
    
    
    package com.forceProxyPattern;
    
    public class Client {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            //定义一个游戏的角色
            IGamePlayer player = new GamePlayer("李四");
            //获得指定代理
            IGamePlayer proxy = player.getProxy();
            proxy.login("lisi", "123");
            proxy.killBoss();
            proxy.upgrade();
        }
    
    }
    View Code

     

(三)动态代理

  • 动态代理在实现阶段不关心代理谁,而在运行阶段才指定代理哪一个对象;
  • 一个非常流行的编程方式叫做面向横切面编程(Aspect Oriented Programming-AOP),其核心就是采用了动态代理机制。
  • Demo Coding:
  • public interface Subject {
        //业务操作
        public void doSomething(String str);
    }
    
    public class RealSubject implements Subject {
        //具体的业务操作实现
        public void doSomething(String str) {
            System.out.println("do something..");
        }
    }
    
    //动态代理的Handler类
    public class MyInvocationHandler implements InvocationHandler {
        //被代理的对象
        private Object target = null;
        //通过构造函数传递一个对象
        public MyInvocationHandler(Object target) {
            this.target = target;
        }
        
        //代理方法
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //执行被代理的方法
            return method.invoke(this.target, args);
        }
        
    }
    
    public class Client {
    
        public static void main(String[] args) {
    //        // TODO Auto-generated method stub
            //定义一个主题
            Subject subject = new RealSubject();
            //定义一个Handler
            InvocationHandler handler = new MyInvocationHandler(subject);
            //获得类的class loader
            ClassLoader cl = subject.getClass().getClassLoader();
            //动态产生一个代理者
            Subject proxy = (Subject) Proxy.newProxyInstance(cl, new Class[]{Subject.class}, handler);
            
            proxy.doSomething("Finish");
    
        }
    
    }
    View Code

     

 六。原型模式(Prototype Pattern)

 Definition: Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

  •  原型模式的核心是一个clone方法,通过该方法进行对象的拷贝,java提供了一个Cloneable接口来标识这个对象是可以拷贝的,JVM中只有这个标记的对象才有可能被拷贝;
  • 原型模式通用代码:
    • public class PrototypeClass implements Cloneable {
          //覆写父类中的方法
      
          @Override
          public PrototypeClass clone() {
              PrototypeClass prototypeClass = null;
              try {
                  prototypeClass = (PrototypeClass) super.clone();
              } catch(CloneNotSupportedException e) {
                  e.printStackTrace();
              }
              return prototypeClass;
          }
      }
      View Code
  • 优点:
    • 原型模式是在内存二进制流的拷贝,比直接new一个对象性能好很多,特别是在一个循环体内产生大量对象的时候;
    • 逃避构造函数的约束:直接在内存中拷贝,构造函数是不会被执行的。
  • 使用场景:
    • 资源优化场景:类初始化需要非常多的资源,包括数据、硬件资源等;
    • 性能和安全要求的场景:用过new产生一个对象需要非常繁琐的数据准备货访问权限,则可以使用原型模式;
    • 一个对象多个修改者的场景:一个对象需要提供给其他对象访问,而且各个调用者可能需要修改其值时。
    • 在实际的项目中,原型模式一般与工厂模式一起出现,用过clone方法创建一个对象,然后由工厂方法提供给调用者。
  • 深拷贝与浅拷贝:
    • 浅拷贝:Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原声对象的呢哦不元素地址。(即拷贝的仅仅是内部对象的地址)
    • 深拷贝:拷贝的是对象本身
    • 二者分开使用
  • final与clone的相爱相杀:若想使用clone,就不要加final关键字了。

    

 

 

 

(-------------------未完待续----------------------)