设计模式
设计模式分类:
设计模式分为三类,创建型模式,结构型模式,行为型模式
创建型模式:
1、工厂方法模式
2、抽象工厂模式
3、单例模式
4、建造者模式
5、原型模式
结构型模式:
1、适配器模式
2、装饰器模式
3、代理模式
4、外观模式
5、桥接模式
6、组合模式
7、享元模式
行为型模式:
1、策略模式
2、模板方法模式
3、观察者模式
4、迭代子模式
5、责任链模式
6、命令模式
7、备忘录模式
8、状态模式
9、访问者模式
10、中介者模式
11、解释器模式
并发型模式和线程池模式
设计模式的六大原则
1、开闭原则(open close principle) 对扩展开放,对修改关闭
在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(liskov substitution principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,
基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范
3、依赖倒转原则(deoendence inversion principle)
这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(interface segregation principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。
5、迪米特法则(demeter principle) 最少知道法则
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(composite reuse principle)
原则是尽量使用合成/聚合的方式,而不是使用继承
1、工厂方法模式(factory method)
1)普通工厂方法模式建立一个工厂类,对实现同一接口的一些类进行实例的创建
例子:发送邮件和短信
创建两者的共同接口:
public interface Sender{ public void Send(); }创建实现类:
public class MailSender implements Sender { public void Send(){ System.out.println("this is mailsender!"); } } public class SmsSender implements Sender { public void Send(){ System.out.println("this is sms sender!"); } }
public class SendFactory { public Sender produce(String type){ if("mail".equals(type)){ return new MailSender(); }else if("sms".equals(type)){ return new SmsSender(); }else{ System.out.println("please enter the rigth type!"); return null; } } }测试代码:
public class FactoryTest { public void main(String[] args){ SendFactory factory = new SendFactory(); Sender sender = factory.produce("sms"); sender.Send(); } }
public class SendFctory { public Sender produceMail(){ return new MailSender(); } public Sender produceSms(){ return new SmsSender(); } }测试类:
public class FactoryTest { public void main(String[] args){ SendFactory factory = new SendFactory(); Sender sender = factory.produceSms(); sender.Send(); } }
3)静态工厂模式
将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。
public class SendFctory { public static Sender produceMail(){ return new MailSender(); } public static Sender produceSms(){ return new SmsSender(); } }
public class FactoryTest { public void main(String[] args){ Sender sender = SendFactory.produceSms(); sender.Send(); } }工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。
2、抽象工厂模式(abstract factory)
工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。
public interface Sender { public void send(); }
public class MailSender implements Sender { public void Send(){ System.out.println("this is a mailsender!") } } public class SmsSender implements Sender { public void Send(){ System.out.println("this is a smsSender!") } }
public class SendMailFactory implements Provider { public Sender produce(){ return new Mailsender(); } } public class SendSmsFactory implements Provider { public Sender produce(){ return new SmsSender(); } }
再提供一个接口
public interface Provider { public Sender produce(); }
public class Test { public static void main(String[] args){ Provider provide = new SendMailFactory(); Sender sender = provide.produce(); sender.Send(); } }其实这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!
3、单例模式(singleton)
单例对象(Singleton)是一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。这样的模式有几个好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
单例类的创建:
public class Singleton { //持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 public static Singleton instance = null; //私有构造方法,防止被实例化 private Singleton(){ } //静态工程方法,创建实例 public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } //如果该对象被用于序列化,可以保证对象在序列化前后保持一致 public Object readResolve(){ return instance; } }
public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; }
public static Singleton getInstance(){ if(instance == null){ synchronized(instance){ if(instance == null){ instance = new Singleton(); } } } return instance; }
private static class SingletonFactory { private static Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonFactory.instance; }
</pre><pre code_snippet_id="631177" snippet_file_name="blog_20150330_18_6878749" name="code" class="html"><span style="font-family:SimHei;color:#009900;"><strong><em style="background-color: rgb(255, 204, 102);">实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。 同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。这样我们暂时总结一个完美的单例模式:</em></strong></span>
public class Singleton { //私有构造方法,防止被实例化 private Singleton(){ } //使用一个内部类维护单例 private static class SingletonFactory { private static Singleton instance = new Singleton(); } // 获取实例 public static Singleton getInstance(){ return SingletonFactory.instance; } public Object readResolve(){ return getInstance(); } }
public class SingletonTest { private static SingletonTest instance = null; private SingletonTest(){ } private static synchronized void syncInit(){ if(instance == null){ instance = new SingletonTest(); } } public static SingletonTest getInstance(){ if(instance == null){ syncInit(); } return instance; } }
考虑性能的话,整个程序只需创建一次实例,所以性能也不会有什么影响。 采用"影子实例"的办法为单例对象的属性同步更新
public class SingletonTest { private static SingletonTest instance = null; private Vector properties = null; public Vector getProperties(){ return properties; } private SingletonTest(){ } private static synchronized void syncInit(){ if(instance == null){ instance = new SingletonTest(); } } public static SingletonTest getInstance(){ if(instance == null){ syncInit(); } return instance; } public void uodateProperties(){ SingletonTest shadow = new SingletonTest(0; properties = shadow.getProperties(); } }synchronized关键字锁定的是对象,在用的时候,一定要在恰当的地方使用(注意需要使用锁的对象和过程,可能有的时候并不是整个对象及整个过程都需要锁)。
public class Builder { private List<Sender> list = new ArrayList<Sender>(); public void produceMailSender(int count){ for(int i = 0;i < count ;i++ ) { list.add(new MailSender()); } } public void produceSmsSender(int count){ for(int i = 0;i < count;i++){ list.add(new SmsSender()); } } }
public class Test { public static void main(String[] args){ Builder builder = new Builder(); builder.produceMailSender(10); } }
5、原型模式(prototype)
原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。
public class Prototype implements Cloneable { public Object clone() throws CloneNotSupportedException{ Prototype proto = (Prototype)super.clone(); return proto; } }一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,
public class Prototype implements Cloneable,Serializable { private static final long serialVersionUID = 1L; private String str; private SerializableObject obj; //浅复制 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(); ObjectOutputStream ois = new ObjectInputStream(bis); return ois.readObject(); } public void setString(String str){ this.str = str; } public SerializableObject getObj(){ return obj; } public void setObj(SerializableObject obj){ this.obj = obj; } } class SerializableObject implements Serializable { private static final long serialVersionUID = 1L }
创建型模式:
适配器模式
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。首先,我们来看看类的适配器模式,先看类图:
核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口时Targetable,通过Adapter类,将Source的功能扩展到Targetable里,看代码:
public class Source { public void method1(){ System.out.println("This is original method!") } } public interface Targetable { //与原类中的方法相同 public void method1(); //新类的方法 public void method2(); } public class Adapter extends Source implements Targetable { public void method2(){ System.out.println("this is the targetable method!") } }
public class AdapterTest { public static void main(String[] args){ Targetable target = new Adapter(); target.method1(); target.method2(); } }