1、什么是设计模式

设计模式(Design pattern)是一套被重复应用、少数人通晓的、通过分类编目标、代码设计教训的总结。应用设计模式是为了可重用代码、让代码更容易被别人了解、保障代码可靠性。 毫无疑问,设计模式于己于别人于零碎都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。
一些简略的设计模式略过,如常量接口模式、标识类型模式。
以下,将从最简略的设计模式开始讲起:

2、单例模式 Singleton

单例模式是指一个类只能领有惟一的实例。为了保障这一点,咱们必须要限度类的创立。即某个单例类,只能够实例化一次。那怎么才能够做到呢?

 实现思路如下:

给须要单例的类申明公有的构造方法。这样就限度了其余类对此类的随便创立。
在单例类外部,申明本人的动态成员变量,且实例化本人。由在以后类中,是能够拜访本人的所有公有成员及办法的,所以,即便构造方法为公有也能够胜利创建对象。
个别状况下,再提供一个静态方法以返回创立的喻一对象。个别状况下,咱们将此办法取名为newInstace,getInstance等,不过这并不是硬性的规定。
示例代码如下:

public class SingletonDemo {    //私有化构造方法    private SingletonDemo(){}    //申明动态公有成员变量    private static SingletonDemo demo;    //提供动态工厂办法    public static SingletonDemo getInstance(){        if(demo==null){            demo = new SingletonDemo();        }        return demo;    }}

4、多例模式 Multition

既然有单例,就会有多例。多例是指限定一个类的只能创立N(具体数量)个的设计模式。如以下性别类,就只能创立两个实例。实现思路是在本类中申明多个类的实例,并提供静态方法返回不同的实例即可:

第一种实现:

public class Gender {    private String sex;    private Gender(String sex){        this.sex = sex;    }    //男性    private static Gender MALE;    //女性    private static Gender FEMALE;    public static Gender getMale(){        if(MALE==null){            MALE = new Gender("男");        }        return MALE;    }    public static Gender getFemale(){        if(FEMALE==null){            FEMALE = new Gender("女");        }        return FEMALE;    }}

第二种实现:

public class Gender {    private String sex;    private Gender(String sex){        this.sex = sex;    }    //男性    private static Gender MALE;    //女性    private static Gender FEMALE;    static{//动态代码块中初始化        MALE = new Gender("男");        FEMALE = new Gender("女");    }    public static Gender getMale(){        return MALE;    }    public static Gender getFemale(){        return FEMALE;    }}

第三种实现:间接应用枚举

public enum Gender{    MALE("男"),FEMALE("女");    private String sex;    private Gender(String sex){        this.sex=sex;    }    @Override    public String toString() {        return sex;    }}

5、工厂办法模式Factory Method

工厂办法指在一个类外部,提供一个静态方法,返回本人的实例或是其余类的实例。具体是返回本人的实例,还是返回其余类的实例,这个要看具体业务的需要。咱们的数据连接池返回的就是其余对象的实例:

public class FactoryDemo{    private static Connection con;    static{    //在此连贯数据库    con = DriverManager.getConnection(…);}//提供一个动态工厂办法public static Connection getConn(){    return con;}}

6、适配置器模式 Adapter

一个接口,往往定义很多办法,但实现此接口的类,可能只须要几个办法。那么那些多余的办法,占据了咱们大量的代码,将失去意义。那怎么才能够即省去一些无用的办法,又实现此接口呢?这就是适配置器模式。
Awt开发中的Listener大量应用了此模式。如WindowListener和WindowAdapter。
请见下面两个类(WindowListener和WindowAdapter)的源代码。

7、装璜器设计模式(Decorator)也叫包装设计模式(Wrapper)

如果一个类,即是某个类的子类,又领有某个类的一个成员变量,则被叫做包装模式。
如:

public Interface IA{}  //定义一个接口public class B implements IA{  //首先B是IA的子类    private IA ia;              //而后B领有一个IA的成员变量。}

应用装璜器或是包装模式个别是为了加强类的性能。如加强某个办法等。

8、代理模式 Proxy

代理模式的定义:对其余对象提供一种代理以管制对这个对象的拜访。在某些状况下,一个对象不想或者不能间接援用另一个对象,而代理对象能够在客户端和指标对象之间起到中介的作用。
假如有一个Italk接口,有空的办法talk()(谈话),所有的people对象都实现(implements)这个接口,实现talk()办法,前端有很多中央都将people实例化,执行talk办法,起初发现这些前端里有一些除了要谈话以外还要唱歌(sing),那么咱们既不能在Italk接口里减少sing()办法,又不能在每个前端都减少sing办法,咱们只有减少一个代理类talkProxy,这个代理类里实现talk和sing办法,而后在须要sing办法的客户端调用代理类即可,代码如下:

//定义接口interface ITalk {    public void talk(String msg);}//定义一个代理,接管ITalk,并减少一个办法singclass TalkProxy implements ITalk{    private ITalk talker;    private String music;    public TalkProxy(ITalk talker,String music){        this.talker=talker;        this.music = music;    }        @Override    public void talk(String msg) {        talker.talk(msg);        sing();    }    //再多定义一个唱歌办法    private void sing(){        System.err.println("正在唱:"+music);    }}//接口的一个实现类class Tom implements ITalk{    public void talk(String msg) {        System.err.println("正在谈话:"+msg);    }}//测试调用public class ProxyDemo{    public static void main(String[] args) {        TalkProxy proxy = new TalkProxy(new Tom(),"十里香");        proxy.talk("Hello");    }}

9、动静代理 Dync Proxy

在JDK中,Proxy类和InvocationHandler能够在不增加任何代码的状况下加强某个办法:

package cn.arcstack.pattern;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.ArrayList;import java.util.List;//测试代码public class DyncProxyDemo {    public static void main(String[] args) {        List list =(List) MyProxy.getProxy(new ArrayList());        list.add("Hello");    }}//书写代理类class MyProxy implements InvocationHandler{    //申明被代理之前的对象    private Object src;    //公有构造方法    private MyProxy(Object src){        this.src=src;    }    //提供一个静态方法以返回被代理当前的对象    public static Object getProxy(Object src){        Object dest = null;//被代理当前的对象        try{            //解决代理的外围代码            dest = Proxy.newProxyInstance(MyProxy.class.getClassLoader(),                        src.getClass().getInterfaces(),                        new MyProxy(src));        }catch(Exception e){            throw new RuntimeException(e.getMessage(),e);        }        return dest;    }    //拦挡办法    public Object invoke(Object proxy, Method method, Object[] args)            throws Throwable {        System.err.println("耿直执行办法:"+method.getName());        Object oo = method.invoke(src, args);        return oo;    }    }

10、观察者模式Observer

观察者模式又叫做公布订阅模式。在此种模式中,一个指标物件治理所有相依于它的观察者物件,并且在它自身的状态扭转时被动发出通知。这通常透过呼叫各观察者所提供的办法来实现。此种模式通常被用来实作事件处理零碎。如Awt中的监听器Listener都是采纳了种模式。

在此种模式下,观察者只是一个接口,即定义一个标准,具体的实现应该是客户端实现。就像Swing中的注册一个监听器一样如:
JFrame frame = new Jframe();//申明被察看,被监听者对象frame.addWindowListener(new WindowListener(){…});//增加一个实现WindowListener的观察者frame.setVisible(true);    //执行一些后续的操作,只有注册了观察者,就会被观察者所监听到

示例代码如下:

public class ObserverDemo {    public static void main(String[] args) {        //杰克逊对象        Singer jackson = new Singer();        //注册观察者        jackson.addListener(new SingListener() {            public void listener(Singer singer) {                System.err.println("监听到了手的正在唱歌。。。。");            }        });        //唱歌        jackson.sing();    }}//设置一个监听器接口-监听谁在唱歌interface SingListener{    public void listener(Singer singer);}//一个可能的被监听者class Singer{    //申明观察者    private SingListener listener;    public void addListener(SingListener sl){        this.listener=sl;    }    public void sing(){        //判断是否有观察者        if(this.listener!=null){            this.listener.listener(this);        }        System.err.println("歌手正在唱歌");    }}

给观察者增加一个察看事件对象,SingEvent,以便于解藕:
残缺的示例代码如下:

package cn.arcstack.pattern;//测试代码public class ObserverDemo {    public static void main(String[] args) {        Singer jackson = new Singer();        jackson.addListener(new SingListener() {            public void listener(SingEvent event) {                System.err.println("歌手是:"+event.getSource());            }        });        jackson.sing();    }}//设置一个监听器接口-监听谁在唱歌interface SingListener{    public void listener(SingEvent event);}//设计一个事件对象class SingEvent{    //接管事件对象,即被观察者    private Object source;    public SingEvent(Object source){        this.source=source;    }    public Object getSource() {        return source;    }}//一个可能的被监听者class Singer{    //申明观察者    private SingListener listener;    public void addListener(SingListener sl){        this.listener=sl;    }    public void sing(){        //判断是否有观察者        if(this.listener!=null){            this.listener.listener(new SingEvent(this));        }        System.err.println("歌手正在唱歌"+this);    }}

11、策略模式Strategy

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还能够互相替换。策略模式让算法独立于应用它的客户而独立变动。
策略模式的组成
-形象策略角色: 策略类,通常由一个接口或者抽象类实现。
  -具体策略角色:包装了相干的算法和行为。
-环境角色:持有一个策略类的援用,最终给客户端调用。

package cn.arcstack.pattern;/** * 策略模式 */public class StrategyDemo {    public static void main(String[] args) {        Context ctx = new Context(new JavaProgrammer());        ctx.doSth();    }}//设计一个公共的接口interface IStrategy{    public void doSth();}//别离书写多个实现类,有不同的实现策略class JavaProgrammer implements IStrategy{    public void doSth() {        System.err.println("写Java代码");    }}class PhpProgrammer implements IStrategy{    public void doSth() {        System.err.println("写PHP代码");    }}//实现策略类class Context{    private IStrategy strategy;    public Context(IStrategy strategy){        this.strategy = strategy;    }    //具体调用    public void doSth(){        this.strategy.doSth();    }

12、门面设计模式

门面设计模式的构造:

没有门面设计模式的调用办法:

有了门面设计模式的类框架图如下:即由原来的客户端一一调用每一个零碎,批改成一应用一个对立中调用:

具体实现代码略。

13、命令模式Command

在软件系统中,“行为请求者”与“行为实现者”通常出现一种“紧耦合”。但在某些场合,比方要对行为进行“记录、撤销/重做、事务”等解决,这种无奈抵挡变动的紧耦合是不适合的。在这种状况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为形象为对象,实现二者之间的松耦合。这就是命令模式(Command Pattern)

示例代码如下:

package cn.arcstack.pattern;public class CommandDemo {    public static void main(String[] args) {        //命令的接收者只有一个        Receiver receiver = new Receiver();        //定义命令的执行者        Invoker invoker = new Invoker();        //通过Command类具体告诉命令的接收者做什么工作        invoker.setCommand(new CommandA(receiver));        invoker.execute();        //再设置第二个命令        invoker.setCommand(new CommandB(receiver));        invoker.execute();    }}//定义命令abstract class Command{    //定义接管命令对象    protected Receiver receiver;    public Command(Receiver rec){        this.receiver=rec;    }    public abstract void execute();}//指定接收者的工作class Receiver{    public void actionA(){        System.err.println("做第一件事");    }    public void actionB(){        System.err.println("做第二件事");    }}//执行者class Invoker{    //接管一个命令    private Command command;    public void setCommand(Command cmd){        this.command = cmd;    }    //执行命令    public void execute(){        command.execute();    }}//定义两个具体的命令class CommandA extends Command{    public CommandA(Receiver rec) {        super(rec);    }    @Override    public void execute() {        this.receiver.actionA();    }}//定义两个具体的命令class CommandB extends Command{    public CommandB(Receiver rec) {        super(rec);    }    @Override    public void execute() {        this.receiver.actionB();    }}

14、原型模式Prototype

用原型实例指定创建对象的品种,并且通过拷贝这些原型创立新的对象。
Prototype原型模式是一种创立型设计模式,Prototype模式容许一个对象再创立另外一个可定制的对象,基本无需晓得任何如何创立的细节,工作原理是:通过将一个原型对象传给那个要动员创立的对象,这个要动员创立的对象通过申请原型对象拷贝它们本人来施行创立。
它次要面对的问题是:“某些结构复杂的对象”的创立工作;因为需要的变动,这些对象常常面临着激烈的变动,然而他们却领有比较稳定统一的接口。
  如何应用?
  因为Java中的提供clone()办法来实现对象的克隆,所以Prototype模式实现一下子变得很简略。
代码略。

15、亨元模式flyweight

能够了解成为轻量级模式,是一种软件设计模式。
面向对象的思维很好地解决了抽象性的问题,个别也不会呈现性能上的问题。然而在某些状况下,对象的数量可能会太多,从而导致了运行时的代价。那么咱们如何去防止大量细粒度的对象,同时又不影响客户程序应用面向对象的形式进行操作?
见上面的代码:
//应用Integer对象的示例

    Integer b1 = 100;    Integer b2 = 100;    System.err.println(b1==b2);   //true    //因为大量细粒度的对象呈现在128以下,所以,下现的值为false    Integer b3 = 128;    Integer b4 = 128;System.err.println(b3==b4); //false

16、总结

在理论的开发中,单例、多例、工厂、适配置器、代理、装璜、包装是常常应用的发模式,其余模式只须要理解就能够了。

本文由mdnice多平台公布