23种设计模式(1)

一、 设计模式的分类

设计模式一般分为三种类型:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值