java设计模式

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)工厂方法模式,和抽象工厂模式


第一类:通过父类与子类的关系进行实现。第二类:两个类之间。第三类:类的状态。第四类:通过中间类

wKioL1TgbbuBEI86AAFkHaGNVS8292.jpg

你可能感兴趣的:(java,设计模式)