一、 设计模式的分类
设计模式一般分为三种类型:
1、创建型,一共有5种:工厂模式、抽象工厂模式、单例模式、创建者模式、原型模式。
2、结构型:一共有7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
3、行为型:一共有11种:策略模式,模块方法模式,观察者模式、迭代子模式、责任链模式、命令模式、通讯录模式、状态模式、中介者模式、访问者模式、解释器模式。
二、 设计模式的原则
一般分为六大原则:
1、开闭原则:对扩展开放,对修改关闭。为了使程序的扩展性好,易于维护和升级。在程序需要拓展的时候,我们不能去修改代码,必须实现一个热插拔效果。
2、里氏代换原则:实现抽象化
3、依赖倒转原则:针对接口编程,依赖抽象而不依赖具体。
4、接口隔离原则:使用多个隔离的接口。降低耦合,降低依赖。
5、迪米特法则(最少知道原则):一个实体尽量少的与其他实体发生相互作用,使功能模块相对独立。
6、合成复用原则:尽量使用合成/聚合的方式,而不是使用继承。
三、 23种设计模式之创建型模式
1、 工厂模式
建立一个工厂类,对实现了同一接口的一些类进行实例的创建。一般我们用静态工厂方法模式。
工厂模式适合:凡是出现了大量的对象需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。
实例
1、先编写一个接口
public interface Call {
void call();
}
2、再写两个类实现上面的Call接口
public class AndroidPhoneCall implements Call {
@Override
public void call() {
System.out.println("Android Phone Call");
}
}
public class IPhoneCall implements Call{
@Override
public void call() {
System.out.println("IPhoneCall");
}
}
3、创建工厂类,实例化上面的两个类
public class Factory {
public static Call androidPhoneCall(){
return new AndroidPhoneCall();
}
public static Call iPhoneCall(){
return new IPhoneCall();
}
}
4、测试
public class Test {
public static void main(String []args){
Call androidPhoneCall = Factory.androidPhoneCall();
Call iPhoneCall = Factory.iPhoneCall();
androidPhoneCall.call();
iPhoneCall.call();
}
}
5、运行结果
Android Phone Call
IPhoneCall
2、 抽象工厂模式
上面讲到的工厂模式有一个问题,类的创建依赖工厂类,此时如果想要拓展程序,必须得对工厂类进行修改。此时我们可以用到抽象工厂模式,创建多个工厂类,这样一旦增加新的功能,直接增加新的工厂类即可。
例如上面工厂模式的例子,此时如果需要加入一个塞班手机的Call方法,我们就要修改Factory类的代码了。不符合我们的闭包原则,使用抽象工厂模式,就可以解决这个问题。
实例
1、创建工厂类的抽象方法
public interface PhoneCall {
Call Phone();
}
2、给每个对象创建一个工厂类
public class AndroidPhoneFactory implements PhoneCall {
@Override
public Call Phone() {
return new AndroidPhoneCall();
}
}
public class IPhoneFactory implements PhoneCall {
@Override
public Call Phone() {
return new IPhoneCall();
}
}
此处扩展的话可添加一个塞班手机的工厂类
public class SaibanFactory implements PhoneCall {
@Override
public Call Phone() {
return new SaibanPhoneCall();
}
}
3、继续保留前面的AndroidPhoneCall类和IPhoneCall类不变,添加SaibanPhoneCall类
public class SaibanPhoneCall implements Call{
@Override
public void call() {
System.out.println("Saiban Phone Call");
}
}
4、测试
public class Test {
public static void main(String []args){
PhoneCall phoneCall = new AndroidPhoneFactory();
Call androidPhoneCall = phoneCall.Phone();
androidPhoneCall.call();
PhoneCall iphoneCall = new IPhoneFactory();
Call iPhoneCall = iphoneCall.Phone();
iPhoneCall.call();
PhoneCall phoneCall1 = new SaibanFactory();
Call saibanPhoneCall = phoneCall1.Phone();
saibanPhoneCall.call();
}
}
5、运行结果
Android Phone Call
IPhoneCall
Saiban Phone Call
3、 单例模式
单例模式是一种常见的设计模式。有几个好处:
1、某些类创建频繁,对于一些大型的对象,这是一笔很大的系统开销。
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。
3、保证核心服务器独立控制整个程序。
实例
public class Singleton {
//持有私有静态实例,防止被引用。此处赋值为null,为的就是实现延迟加载
private static Singleton instance = null;
//私有构造法 ,防止被实例化
private Singleton() {
}
//静态工程方法,创建实例
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
这个类可以满足基本要求,但是,像这样毫无线程安全保护的类,如果我们把它放入多线程的环境下,肯定就会出现问题了,如何解决?我们首先会想到对getInstance方法加synchronized关键字
如:
public class Singleton {
//持有私有静态实例,防止被引用。此处赋值为null,为的就是实现延迟加载
private static Singleton instance = null;
//私有构造法 ,防止被实例化
private Singleton() {
}
//静态工程方法,创建实例
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
但是,synchronized关键字锁住的是这个对象,这样的用法,在性能上会有所下降,因为每次调用getInstance(),都要对对象上锁,事实上,只有在第一次创建对象的时候需要加锁,之后就不需要了。
如:
public class Singleton {
//持有私有静态实例,防止被引用。此处赋值为null,为的就是实现延迟加载
private static Singleton instance = null;
//私有构造法 ,防止被实例化
private Singleton() {
}
//静态工程方法,创建实例
public static Singleton getInstance(){
if(instance == null){
synchronized (instance){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
实际情况是,单例模式使用内部类来维护单例的实现,JVM内部的机制能够保证当一个类被加载的时候, 这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就不用担心上面的问题。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题。
public class Singleton {
//私有构造法 ,防止被实例化
private Singleton() {
}
//静态工程方法,创建实例
private static class SingletonFactory{
private static Singleton instance = new Singleton();
}
private static Singleton getInstance() {
return SingletonFactory.instance;
}
}
这也有一个问题,如果在构造函数中抛出异常,实例将永远得不到创建,也会出错。
所以我们还是视具体情况而定,选择合适的方法。
4、 builder创建者模式
建造模式是对象的创建模式。建造模式可以将一个产品的内部表象(internal representation)与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。
参考:http://www.cnblogs.com/java-my-life/archive/2012/04/07/2433939.html
实例
1、创建产品类
public class Product {
private String part1;
private String part2;
public String getPart1() {
return part1;
}
public void setPart1(String part1) {
this.part1 = part1;
}
public String getPart2() {
return part2;
}
public void setPart2(String part2) {
this.part2 = part2;
}
}
2、实现builder的抽象类
public interface Builder {
void buildPart1();
void buildepart2();
Product getProduct();
}
3、实现builder的具体类
public class ConcreatBuilder implements Builder {
private Product product = new Product();
@Override
public void buildPart1() {
product.setPart1("part1");
}
@Override
public void buildepart2() {
product.setPart2("part2");
}
@Override
public Product getProduct() {
return product;
}
}
4、实现Director类
public class Director {
private Builder builder;
public Director(Builder builder){
this.builder = builder;
}
public void construct(){
builder.buildPart1();
builder.buildepart2();
}
}
5、测试
public class BuilderTest {
public static void main(String []args){
Builder builder = new ConcreatBuilder();
Director director = new Director(builder);
director.construct();
Product product = builder.getProduct();
System.out.println(product.getPart1());
System.out.println(product.getPart2());
}
}
6、运行结果
part1
part2
5、 原型模式
原型模式要求对象实现一个可以“克隆”自身的接口,这样就可以通过复制一个实例对象本身来创建一个新的实例。这样一来,通过原型实例创建新的对象,就不再需要关心这个实例本身的类型,只要实现了克隆自身的方法,就可以通过这个方法来获取新的对象,而无须再去通过new来创建。
原型模式有两种表现形式:
1、简单形式
2、登记形式
这两种表现形式仅仅是原型模式的不同实现。
实例
- 1、简单形式的实例
public interface Prototype{
/**
* 克隆自身的方法
* @return 一个从自身克隆出来的对象
*/
public Object clone();
}
public class ConcretePrototype1 implements Prototype {
public Prototype clone(){
//最简单的克隆,新建一个自身对象,由于没有属性就不再复制值了
Prototype prototype = new ConcretePrototype1();
return prototype;
}
}
public class ConcretePrototype2 implements Prototype {
public Prototype clone(){
//最简单的克隆,新建一个自身对象,由于没有属性就不再复制值了
Prototype prototype = new ConcretePrototype2();
return prototype;
}
}
public class Client {
/**
* 持有需要使用的原型接口对象
*/
private Prototype prototype;
/**
* 构造方法,传入需要使用的原型接口对象
*/
public Client(Prototype prototype){
this.prototype = prototype;
}
public void operation(Prototype example){
//需要创建原型接口的对象
Prototype copyPrototype = prototype.clone();
}
}
- 2、登记形式的实例
public interface Prototype{
public Prototype clone();
public String getName();
public void setName(String name);
}
public class ConcretePrototype1 implements Prototype {
private String name;
public Prototype clone(){
ConcretePrototype1 prototype = new ConcretePrototype1();
prototype.setName(this.name);
return prototype;
}
public String toString(){
return "Now in Prototype1 , name = " + this.name;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
}
public class ConcretePrototype2 implements Prototype {
private String name;
public Prototype clone(){
ConcretePrototype2 prototype = new ConcretePrototype2();
prototype.setName(this.name);
return prototype;
}
public String toString(){
return "Now in Prototype2 , name = " + this.name;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
}
public class PrototypeManager {
/**
* 用来记录原型的编号和原型实例的对应关系
*/
private static Map<String,Prototype> map = new HashMap<String,Prototype>();
/**
* 私有化构造方法,避免外部创建实例
*/
private PrototypeManager(){}
/**
* 向原型管理器里面添加或是修改某个原型注册
* @param prototypeId 原型编号
* @param prototype 原型实例
*/
public synchronized static void setPrototype(String prototypeId , Prototype prototype){
map.put(prototypeId, prototype);
}
/**
* 从原型管理器里面删除某个原型注册
* @param prototypeId 原型编号
*/
public synchronized static void removePrototype(String prototypeId){
map.remove(prototypeId);
}
/**
* 获取某个原型编号对应的原型实例
* @param prototypeId 原型编号
* @return 原型编号对应的原型实例
* @throws Exception 如果原型编号对应的实例不存在,则抛出异常
*/
public synchronized static Prototype getPrototype(String prototypeId) throws Exception{
Prototype prototype = map.get(prototypeId);
if(prototype == null){
throw new Exception("您希望获取的原型还没有注册或已被销毁");
}
return prototype;
}
}
public class Client {
public static void main(String[]args){
try{
Prototype p1 = new ConcretePrototype1();
PrototypeManager.setPrototype("p1", p1);
//获取原型来创建对象
Prototype p3 = PrototypeManager.getPrototype("p1").clone();
p3.setName("张三");
System.out.println("第一个实例:" + p3);
//有人动态的切换了实现
Prototype p2 = new ConcretePrototype2();
PrototypeManager.setPrototype("p1", p2);
//重新获取原型来创建对象
Prototype p4 = PrototypeManager.getPrototype("p1").clone();
p4.setName("李四");
System.out.println("第二个实例:" + p4);
//有人注销了这个原型
PrototypeManager.removePrototype("p1");
//再次获取原型来创建对象
Prototype p5 = PrototypeManager.getPrototype("p1").clone();
p5.setName("王五");
System.out.println("第三个实例:" + p5);
}catch(Exception e){
e.printStackTrace();
}
}
}
四、 参考资料
1、http://www.cnblogs.com/java-my-life/archive/2012/04/07/2433939.html
2、http://www.cnblogs.com/maowang1991/archive/2013/04/15/3023236.html
3、http://www.cnblogs.com/java-my-life/archive/2012/04/11/2439387.html