http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html
一、单例模式:保证在一个JVM中,该对象只有一个实例存在; 有如下三种实现方法
1) //单例模式---饿汉模式
public class Singleton1 {
//构造方法私有化
private Singleton1(){
}
//在Java指令中创建对象和赋值操作是分开进行的,也就是说instance = new Singleton();语句是分两步执行的.
//使用内部类来实现单例,私有的内部类,会保证赋值给instance的内存初始化完毕.
//使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的,即线程安全的.
private static class SingletonFactory{
private static Singleton1 instance = new Singleton1();
}
//对外开放接口
public static Singleton1 getInstance(){
return SingletonFactory.instance;
}
}
2)//单例模式中的-----饿汉模式
public class Singleton2 {
//静态的私有化属性,这样在类被加载时,就实例话对象,而且类加载时是线程安全的
private static Singleton2 instance = new Singleton2();
//构造方法私有化
private Singleton2() {
}
//对外开放接口
public static Singleton2 getInstance() {
return Singleton2.instance;
}
}
3)//单例模式中的-----赖汉模式
public class Singleton3 {
private static Singleton3 instance = null;
private Singleton3() {
}
//在Java指令中创建对象和赋值操作是分开进行的
//单例模式中的赖汉模式:只有第一次使用时,才实例化对象,这种方式存在线程安全问题,
//需要使用synchronized
public static Singleton3 getInstance() {
if (instance == null) {
synchronized (instance) {
instance = new Singleton3();
}
}
return instance;
}
}
二、原型模式(Prototype):原型模式是创建型的模式,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,
产生一个和原对象类似的新对象。
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原
对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。
简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。
1)写一个原型类
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Prototype implements Cloneable, Serializable {
private static final long serialVersionUID = 1L;
/* 浅复制 */
public Object clone() throws CloneNotSupportedException {
Prototype proto = (Prototype) super.clone();
return proto;
}
/* 深复制 :要实现深复制,需要采用流的形式读入当前对象的二进制输入,
再写出二进制数据对应的对象*/
public Object deepClone() throws IOException, ClassNotFoundException {
/* 写入当前对象的二进制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 读出二进制流产生的新对象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
2)想要实现克隆的对象继承Prototype, 这样当此对象要进行克隆时,就可以调用deepClone()方法
了;
public class UserLogin extends Prototype {
private static final long serialVersionUID = 1L;
private String userName;
private Account account;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
}
三、责任链模式:有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链
上传递,直到某一对象决定处理该请求。但是发出者并不清楚到底最终那个对象会处理
该请求,所以,责任链模式可以实现,在隐瞒客户端的情况下,对系统进行动态的调整
1)//定义链对象上的处理方法
public interface Handler {
public void operator();
}
2)定义抽象类,是为了设置后继节点
public abstract class AbstractHandler {
private Handler handler;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
}
3)
public class MyHandler extends AbstractHandler implements Handler {
private String name;
public MyHandler(String name) {
this.name = name;
}
public void operator() {
System.out.println(name + "deal!");
if (getHandler() != null) {
getHandler().operator();
}
}
}
4)执行责任链
public class Ab {
public static void main(String[] args) {
MyHandler h1 = new MyHandler("h1");
MyHandler h2 = new MyHandler("h2");
MyHandler h3 = new MyHandler("h3");
//
h1.setHandler(h2);
h2.setHandler(h3);
h1.operator();
}
}
四、命令模式:命令模式的目的就是达到命令的发出者和执行者之间解耦,实现请求和执行分开
Invoker是调用者(司令员),Receiver是被调用者(士兵),MyCommand是命令,实现了Command接口,持有接收对象,看实现代码
下面的代码,执行者也可以接口化
1)//执行者(士兵)
public class Receiver {
public void action() {
System.out.println("command received!");
}
}
2)//命令接口
public interface Command {
public void exe();
}
3)//命令实现类,持有执行者
public class MyCommand implements Command {
private Receiver receiver;
public MyCommand(Receiver receiver) {
this.receiver = receiver;
}
public MyCommand() {
}
public void exe() {
receiver.action();
}
}
4)//下命令者(司令员),持有命令
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void action() {
command.exe();
}
}
5)测试方法
public static void main(String[] args) {
//执行者
Receiver receiver = new Receiver();
//命令,持有执行者
Command cmd = new MyCommand(receiver);
//下命令者,持有命令
Invoker invoker = new Invoker(cmd);
//下令执行
invoker.action();
}
五、模板方法模式:一个抽象类中,有一个主方法,再定义1...n个方法,可以是抽象的,也可以是实际
的方法,定义一个类,继承该抽象类,重写抽象方法,通过调用抽象类,实现对子类的调用
就是在AbstractCalculator类中定义一个主方法calculate,calculate()调用spilt()等,Plus和
Minus分别继承AbstractCalculator类,通过对AbstractCalculator的调用实现对子类的调用。
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子
类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
1)抽象类中有一个抽象方法,作为模板方法
public abstract class AbstractCalculator {
/*主方法,实现对本类其它方法的调用*/
public final int calculate(String exp, String opt) {
int array[] = split(exp, opt);
return calculate(array[0], array[1]);
}
/*被子类重写的方法*/
abstract public int calculate(int num1, int num2);
public int[] split(String exp, String opt) {
String array[] = exp.split(opt);
//
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
2)子类,重写模板的抽象方法
public class Plus extends AbstractCalculator {
@Override
public int calculate(int num1, int num2) {
return num1 + num2;
}
}
3)测试方法
public static void main(String[] args) {
String exp = "8-8";
//String.split方法的说明
//http://www.cnblogs.com/mingforyou/archive/2013/09/03/3299569.html
AbstractCalculator cal = new Minus();
int result = cal.calculate(exp, "\\-");
System.out.println(result);
}
六、观察者模式(Observer):观察者模式类似订阅,当你订阅了该文章,如果后续有更新,会及时通知你
简单来讲一句话:当一个对象变化时,依赖该对象的对象都会收到通知,并且随着变化!
对象之间是一种一对多的关系.
观察者模式是类和类之间的关系(主题类和观察类之间的关系).
1)//观察者接口
public interface Observer {
//定义当主题发生改变时,观察者要执行的方法
public void update();
}
2)//观察者1
public class Observer1 implements Observer {
public void update() {
System.out.println("observer1 has received!");
}
}
3)//观察者2
public class Observer2 implements Observer {
public void update() {
System.out.println("observer2 has received!");
}
}
4)//主题接口:定义通用的方法(包括操作观察者的方法,以及观察者自身要执行的方法)
public interface Subject {
//增加观察者
public void add(Observer observer);
//删除观察者
public void del(Observer observer);
//通知所有的观察者
public void notifyObservers();
//自身的操作
public void operation();
}
5)//抽象主题类:实现通用的方法,特殊的方法,由子抽象类的子类去实现
public abstract class AbstractSubject implements Subject {
//线程安全
private Vector<Observer> vector = new Vector<Observer>();
//添加观察者
public void add(Observer observer) {
vector.add(observer);
}
//删除观察者
public void del(Observer observer) {
vector.remove(observer);
}
//通知所有的观察者
public void notifyObservers() {
Enumeration<Observer> enumo = vector.elements();
while (enumo.hasMoreElements()) {
enumo.nextElement().update();
}
}
}
6)//抽象主题类的子类
public class MySubject extends AbstractSubject {
//自身修改,通知所有的观察者
public void operation() {
System.out.println("update self!");
notifyObservers();
}
}
7)测试方法
public static void main(String[] args) {
//创建主题对象
Subject sub = new MySubject();
//主题对象添加观察着(订阅者)
sub.add(new Observer1());
sub.add(new Observer2());
//执行主题(触发主题发生操作)
sub.operation();
}
七、策略模式(strategy)
策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到
使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计
一个抽象类(可有可无,属于辅助类),提供辅助函数
策略模式的决定权在用户,系统本身提供不同算法的实现,策略模式多用在算法决策系统中,外部用户只
需要决定用哪个算法即可。
策略模式与模板方法模式有何区别呢?
模板方法模式:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可
以在不改变算法结构的情况下,重新定义算法中的某些步骤
策略模式:定义一个算法家族,并让这些算法可以互换。正因为每一个算法都被封装起来了,所以客户
可以轻易地使用不同的算法
模板方法模式意图与策略模式意图不一样:
模板方法模式工作是定义一个算法的大纲,而由其子类定义其中某些步骤的内容。这么一来,其在算法
中的个别步骤可以有不同的实现细节,但是算法的结构依然维持不变。不过策略模式就不一样了。似乎
必须放弃对算法的控制。模板方法模式对算法有更多的控制权,而且不会重复代码。
策略模式:因为使用了组合,所以更加有弹性。依赖程度没有模板方法模式那么深。不依赖任何对象,
整个算法自己搞定。
1)//统一接口
public interface ICalculator {
public int calculate(String exp);
}
2)//抽象类,起辅助作用
public abstract class AbstractCalculator {
public int[] split(String exp,String opt){
String array[] = exp.split(opt);
int arrayInt[] = new int[2];
arrayInt[0] = Integer.parseInt(array[0]);
arrayInt[1] = Integer.parseInt(array[1]);
return arrayInt;
}
}
3)算法1
public class Plus extends AbstractCalculator implements ICalculator {
public int calculate(String exp) {
int arrayInt[] = split(exp, "\\+");
return arrayInt[0] + arrayInt[1];
}
}
4)算法2
public class Minus extends AbstractCalculator implements ICalculator {
public int calculate(String exp) {
int arrayInt[] = split(exp, "-");
return arrayInt[0] - arrayInt[1];
}
}
5)//测试方法
public static void main(String[] args) {
String exp = "2+8";
//调用具体的算法,这个由外部用户决定
ICalculator cal = new Plus();
int result = cal.calculate(exp);
System.out.println(result);
}
八、状态模式(State)
核心思想就是:当对象的状态改变时,同时改变其行为,很好理解!就拿QQ来说,有几种状态,在线、
隐身、忙碌等,每个状态对应不同的操作,而且你的好友也能看到你的状态,所以,状态模式就两
点:
1、可以通过改变状态来获得不同的行为。
2、你的好友能同时看到你的变化.
1)//状态类的核心类,状态类所有的方法都写在状态类中,至于何种状态,能调用哪些方法,在状态模式
的切换类中定义
public class State {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public void method1() {
System.out.println("execute the first opt!");
}
public void method2() {
System.out.println("execute the second opt!");
}
}
2)// 状态模式的切换类
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
//状态类中定义通用的方法,内部实现根据不同的状态,调用状态对应的不同方法
public void method() {
if (state.getValue().equals("state1")) {
state.method1();
} else if (state.getValue().equals("state2")) {
state.method2();
}
}
}
3)//测试方法
public static void main(String[] args) {
//定义状态类
State state = new State();
//定义状态切换类
Context context = new Context(state);
//设置第一种状态 ,执行状态类的 mehtod方法
state.setValue("state1");
context.method();
//设置第二种状态 ,执行状态类的 mehtod方法
state.setValue("state2");
context.method();
}
九、适配器模式:核心思想,就是解决目标接口和原有接口不兼容而引入的.开发中遇到这类情况,就应
该尝试使用适配器。
作用: .)透明:通过适配器,客户端调用同一个接口,对客户是透明的;
.)复用:复用了现存的类,解决了现存类和复用环境要求不一致的问题。
.)低耦合:将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,
而无需修改原有代码(遵循开闭原则)
1) 组合:
采用组合方式的适配器称为对象适配器
特点:把“被适配者”作为一个对象,组合到适配器类中,以修改目标接口包装被适配者。
被适配类----》适配器类-----》目标接口
如果将适配器中,组合被适配者的接口的话,那此适配器就可以适配,"被适配接口的任何子类"
2)继承:
采用继承方式的称为类适配器
特点:通过多重继承不兼容接口,实现对目标接口的匹配,单一的为某个类二实现适配。
具体实现:适配器类,继承被适配者类,实现目标接口;这样在实现方法中调用被适配者的方法
3)两者的区别:
.)继承适配器,继承了“被适配者类”,单一的为这个类而实现适配的;如果“被适配者类“还有
子类的话,就需再为子类再创建适配器;因为java是单一继承
.)对象适配器,如果"被适配者"有子类的话,同样适配
4) 适配器模式是一种思想,不要以为只有以上两种;适配器会有很多的变体,只要是把不兼容的转换
成兼容的,匹配的,我们就叫它适配器。
三种适配器模式的应用场景:
.)类的适配器模式:当希望将一个类转换成满足另一个新接口的类时,可以使用类的适配器模式,创建一
个新类,继承原有的类,实现新的接口即可。
.)对象的适配器模式: 当希望将一个对象转换成满足另一个新接口的对象时,可以创建一个Wrapper类,
持有原类的一个实例,在Wrapper类的方法中,调用实例的方法就行
.)接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有
方法,我们写别的类的时候,继承抽象类即可。
十、代理模式(Proxy):代理模式就是多一个代理类出来,替原对象进行一些操作;比如租房子的时候回
去找中介,打官司找法律
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法
1)修改原有的方法来适应。这样违反了“对扩展开放,对修改关闭”的原则。
2)就是采用一个代理类调用原有的方法,且对产生的结果进行控制。这种方法就是代理模式.
使用代理模式,可以将功能划分的更加清晰,有助于后期维护!
代理分静态代理和动态代理:
静态代理代码如下:
1)//原接口
public interface Sourceable {
public void method();
}
2)//原目标
public class Source implements Sourceable {
public void method() {
System.out.println("the original method!");
}
}
3)//代理类实现原接口,这样代理类就可以代替原类使用了
public class Proxy implements Sourceable {
private Source source;
public Proxy() {
super();
this.source = new Source();
}
public void method() {
before();
source.method();
atfer();
}
private void atfer() {
System.out.println("after proxy!");
}
private void before() {
System.out.println("before proxy!");
}
}
4) //测试方法
public static void main(String[] args) {
//使用代理类代替原类使用
Sourceable source = new Proxy();
source.method();
}
静态代理:代理和被代理对象在代理之前是确定的。他们都实现相同的接口或者继承相同的抽象类;
对于相同的代理业务逻辑进行处理,如果要代理不同的被代理对象,需要创建不同的代理类,
这样会导致创建太多的代理类,不灵活,可以使用动态代理;
Jdk动态代理:
1) 只能代理实现了接口的类
2) 没有实现接口的类不能实现jdk的动态代理
3) 创建jdk动态代理的步骤:
.)创建一个实现了java.lang.reflect.InvocationHandler接口的类,必须实现invoke方法(具
体业务逻辑);
.)创建被代理的类以及接口
.)调用Proxy的静态方法,创建一个代理类
newProxyInstance(ClassLoader loader,
Class[]interfaces,InvocationHandlerh)
.) 调用代理类的方法
例子:
//创建具体业务逻辑
publicclass TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
/**
*proxy:被代理对象
*method:被代理对象方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long starttime = System.currentTimeMillis();
method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("运行时间:"+(endtime-starttime));
returnnull;
}
}
//被代理的类和接口
publicclass Car implements Moveable{
@Override
publicvoid move() {
try {
//实现开车
System.out.println("运行中");
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//具体使用jdk动态代理的步骤
publicstaticvoid main(String[] args) {
Car car= new Car();
Class<?> cls = car.getClass();
TimeHandler h = new TimeHandler(car);
Moveable proxy = (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);
//
Class<?> cls2 = proxy.getClass();
LogHandler log = new LogHandler(proxy);
Moveable logProxy = (Moveable)Proxy.newProxyInstance(cls2.getClassLoader(),cls2.getInterfaces(), log);
logProxy.move();
}
cglib动态代理:
针对类来实现代理的
对指定目标类生成一个子类,通过方法拦截技术拦截所有父类方法的调用
//
publicclass CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Classclz) {
enhancer.setSuperclass(clz);
enhancer.setCallback(this);
returnenhancer.create();
}
/**
*拦截所有目标类方法的调用obj
*目标类的实例m
*目标方法的反射对象args
*方法的参数proxy代理类的实例
*/
@Override
public Object intercept(Object obj, Method m, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("运行前log");
// 代理类调用父类的方法
proxy.invokeSuper(obj, args);
System.out.println("运行后log");
returnnull;
}
}
//测试方法
publicstaticvoid main(String[] args) {
CglibProxy cglib= new CglibProxy();
Train t = (Train)cglib.getProxy(Train.class);
t.move();
}
十一、模式总结
1)单例模式:
2)原型模式: 思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象
3)责任链模式 : 有多个对象,每个对象持有对下一个对象的引用,这样就会形成一条链,请求在这条链
上传递,直到某一对象决定处理该请求
4)命令模式: 目的是达到命令的发出者和执行者之间解耦;发出者持有命令接口,命名持有执行者接口
5)模板方法模式: 抽象类的抽象方法,由子类实现;使用时通过调用抽象类,实现对子类的调用
6)观察者模式: 类似订阅,当你订阅的文章有更新,会及时通知你;具体实现:定义一个目标接口,一个
AbstractSubject(其持有一 个集合,封装观察者),所有的具体目标都继承
AbstractSubject,当接口发生改变时,将调用通知方法
7)策略模式
8)状态模式
9)适配器模式
10)代理模式
11)工厂方法模式,和抽象工厂模式
第一类:通过父类与子类的关系进行实现。第二类:两个类之间。第三类:类的状态。第四类:通过中间类