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多平台公布