总结:设计模式

1.单例设计模式

       所谓单例设计模式简单说就是无论程序如何运行,采用单例设计模式的类(Singleton类)永远只会有一个实例化对象产生。具体实现步骤如下:

      (1) 将采用单例设计模式的类的构造方法私有化(采用private修饰)。

      (2) 在其内部产生该类的实例化对象,并将其封装成private static类型。

      (3) 定义一个静态方法返回该类的实例。

         示例代码如下:

class Singleton {   
    private static Singleton instance = new Singleton();// 在内部产生本类的实例化对象  
  
    public static Singleton getInstance() { // 通过静态方法返回instance对象  
        return instance;   
    }   
  
    private Singleton() { // 将构造方法封装为私有化  
    }   
  
    public void print() {   
        System.out.println("Hello World!!!");   
    }   
}   
  
public class SingletonDemo {   
    public static void main(String args[]) {   
        Singleton s1 = null; // 声明对象  
        Singleton s2 = null; // 声明对象  
        Singleton s3 = null; // 声明对象  
        s1 = Singleton.getInstance(); // 取得实例化对象  
        s2 = Singleton.getInstance(); // 取得实例化对象  
        s3 = Singleton.getInstance(); // 取得实例化对象  
        s1.print(); // 调用方法   
        s2.print(); // 调用方法   
        s3.print(); // 调用方法   
    }   
}
单例模式实现方式;

/**  
 *   
 * 单例模式的实现:饿汉式,线程安全 但效率比较低  
 */  
public class SingletonTest {   
  
    private SingletonTest() {   
    }   
  
    private static final SingletonTest instance = new SingletonTest();   
  
    public static SingletonTest getInstancei() {   
        return instance;   
    }   
  
}
/**  
 * 单例模式的实现:饱汉式,非线程安全   
 *   
 */  
public class SingletonTest {   
    private SingletonTest() {   
    }   
  
    private static SingletonTest instance;   
  
    public static SingletonTest getInstance() {   
        if (instance == null)   
            instance = new SingletonTest();   
        return instance;   
    }   
}
/** 
 * 线程安全,但是效率非常低 
 * @author vanceinfo 
 * 
 */  
public class SingletonTest {  
    private SingletonTest() {  
    }  
  
    private static SingletonTest instance;  
  
    public static synchronized SingletonTest getInstance() {  
        if (instance == null)  
            instance = new SingletonTest();  
        return instance;  
    }  
}

最后一种推荐:

/**  
 * 线程安全  并且效率高  
 *  
 */  
public class SingletonTest {   
    private static SingletonTest instance;   
  
    private SingletonTest() {   
    }   
  
    public static SingletonTest getIstance() {   
        if (instance == null) {   
            synchronized (SingletonTest.class) {   
                if (instance == null) {   
                    instance = new SingletonTest();   
                }   
            }   
        }   
        return instance;   
    }   
}

但是个人还是最喜欢第一种,简单,好理解,线程安全。

单例模式的好处:

1、节省不必要的内存开销,屏蔽对象创建的复杂性。

2、因为不需要重新创建对象,因此访问速度快。

3、容易驾驭产生的对象,因为只有一个。在不使用单例的情况下,往往会产生很多对象,这些对象的处理是通过系统的守护线程垃圾收集器去处理,自己不需要去主动清理,但是你并不知道垃圾清理的效果怎么样,对于有些无用的对象可能对系统产生的影响是我们驾驭不了的,当由于垃圾对象导致系统出现问题的bug可能非常难解决。

单例的使用:

1、spring框架产生对象默认就是单例的。

2、读取配置文件的类可以设置为单例。

3、数据库连接可以设置为单例,但是不是很好,因为连接会过期,但是对象可能还存在,因此单例获取的对象可能已经连接失效。

4、项目里面的service,dao类的对象其实只需要一个就行了,这里可以使用单例的方式获取service和dao。

2.工厂设计模式

       程序在接口和子类之间加入了一个过渡端,通过此过渡端可以动态取得实现了共同接口的子类实例化对象。

      示例代码如下:

interface Animal { // 定义一个动物的接口  
    public void say(); // 说话方法  
}   
  
class Cat implements Animal { // 定义子类Cat  
    @Override  
    public void say() { // 覆写say()方法  
        System.out.println("我是猫咪,喵呜!");   
    }   
}   
  
class Dog implements Animal { // 定义子类Dog  
  
    @Override  
    public void say() { // 覆写say()方法  
        System.out.println("我是小狗,汪汪!");   
    }   
}   
  
class Factory { // 定义工厂类  
    public static Animal getInstance(String className) {   
        Animal a = null; // 定义接口对象  
        if ("Cat".equals(className)) { // 判断是哪个子类的标记  
            a = new Cat(); // 通过Cat子类实例化接口  
        }   
        if ("Dog".equals(className)) { // 判断是哪个子类的标记  
            a = new Dog(); // 通过Dog子类实例化接口  
        }   
        return a;   
    }   
}   
  
public class FactoryDemo {   
  
    public static void main(String[] args) {   
        Animal a = null; // 定义接口对象  
        a = Factory.getInstance(args[0]); // 通过工厂获取实例  
        if (a != null) { // 判断对象是否为空  
            a.say(); // 调用方法   
        }   
    }   
}

工厂模式的好处:


如果有许多地方都需要生成A的对象,那么你需要写很多A  a=new A()。
如果需要修改的话,你要修改许多地方。
但是如果用工厂模式,你只需要修改工厂代码。其他地方引用工厂,可以做到只修改一个地方,其他代码都不动,就是解耦了。



3.适配器模式

        如果一个类要实现一个具有很多抽象方法的接口,但是本身只需要实现接口中的部分方法便可以达成目的,所以此时就需要一个中间的过渡类,但此过渡类又不希望直接使用,所以将此类定义为抽象类最为合适,再让以后的子类直接继承该抽象类便可选择性的覆写所需要的方法,而此抽象类便是适配器类。

      示例代码如下:


interface Window {// 定义Window窗口接口,表示窗口操作  
    public void open();// 窗口打开  
  
    public void close();// 窗口关闭  
  
    public void iconified();// 窗口最小化  
  
    public void deiconified();// 窗口恢复  
  
    public void activated();// 窗口活动  
}   
  
// 定义抽象类实现接口,在此类中覆写方法,但是所有的方法体为空   
abstract class WindowAdapter implements Window {   
    public void open() {   
    };// 窗口打开   
  
    public void close() {   
    };// 窗口关闭   
  
    public void iconified() {   
    };// 窗口最小化   
  
    public void deiconified() {   
    };// 窗口恢复   
  
    public void activated() {   
    };// 窗口活动   
}   
  
// 子类继承WindowAdapter抽象类,选择性实现需要的方法   
class WindowImpl extends WindowAdapter {   
    public void open() {   
        System.out.println("窗口打开");// 实现open()方法  
    }   
  
    public void close() {   
        System.out.println("窗口关闭");// 实现close()方法  
    }   
}   
  
public class AdapterDemo {   
    public static void main(String args[]) {   
        Window win = new WindowImpl(); // 实现接口对象  
        // 调用方法   
        win.open();   
        win.close();   
    }   
}


4.生产者--消费者模式

4.1、实例讲解

这种模式我现在经常用(即ActiveMQ):

    生产者:就是生产数据的,如我经常往队列里面塞数据,我就是生产者。

    消费者:从队列里面取数据并处理,这就是消费者。

还有一个使用的例子就是线程池:Executor接口

4.2.分析

以上的队列就是个缓冲区。

为了不至于太抽象,我们举一个寄信的例子(虽说这年头寄信已经不时兴,但这个例子还是比较贴切的)。假设你要寄一封平信,大致过程如下:

1、你把信写好——相当于生产者制造数据

2、你把信放入邮筒——相当于生产者把数据放入缓冲区

3、邮递员把信从邮筒取出——相当于消费者把数据取出缓冲区

4、邮递员把信拿去邮局做相应的处理——相当于消费者处理数据

★优点

可能有同学会问了:这个缓冲区有什么用捏?为什么不让生产者直接调用消费者的某个函数,直接把数据传递过去?搞出这么一个缓冲区作甚?

其实这里面是大有讲究的,大概有如下一些好处。

◇解耦

假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。

接着上述的例子,如果不使用邮筒(也就是缓冲区),你必须得把信直接交给邮递员。有同学会说,直接给邮递员不是挺简单的嘛?其实不简单,你必须得认识谁是邮递员,才能把信给他(光凭身上穿的制服,万一有人假冒,就惨了)。这就产生和你和邮递员之间的依赖(相当于生产者和消费者的强耦合)。万一哪天邮递员换人了,你还要重新认识一下(相当于消费者变化导致修改生产者代码)。而邮筒相对来说比较固定,你依赖它的成本就比较低(相当于和缓冲区之间的弱耦合)。

◇支持并发(concurrency)

生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。

使用了生产者/消费者模式之后,生产者和消费者可以是两个独立的并发主体(常见并发类型有进程和线程两种,后面的帖子会讲两种并发类型下的应用)。生产者把制造出来的数据往缓冲区一丢,就可以再去生产下一个数据。基本上不用依赖消费者的处理速度。

其实当初这个模式,主要就是用来处理并发问题的。

从寄信的例子来看。如果没有邮筒,你得拿着信傻站在路口等邮递员过来收(相当于生产者阻塞);又或者邮递员得挨家挨户问,谁要寄信(相当于消费者轮询)。不管是哪种方法,都挺土的。

◇支持忙闲不均

缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

为了充分复用,我们再拿寄信的例子来说事。假设邮递员一次只能带走1000封信。万一某次碰上情人节(也可能是圣诞节)送贺卡,需要寄出去的信超过1000封,这时候邮筒这个缓冲区就派上用场了。邮递员把来不及带走的信暂存在邮筒中,等下次过来时再拿走。

费了这么多口水,希望原先不太了解生产者/消费者模式的同学能够明白它是怎么一回事。然后在下一个帖子中,我们来说说如何确定数据单元。

另外,为了方便阅读,把本系列帖子的目录整理如下:

1、如何确定数据单元

2、队列缓冲区

3、队列缓冲区

4、双缓冲区

5.策略模式


策略模式 定义了算法族,并分别封装起来,让它们之间可以相互替换。此模式让算法的变化独立于使用算法的客户。

实际应用:魂斗罗的游戏大家应该都不陌生。在游戏中能够吃很多道具,来更换子弹的类型,有炫弹,散弹,直弹,火箭弹等等。这个我们就可以设计成策略模式。

分析:策略模式主要是把主体类的行为(动作)(在魂斗罗中指的是把使用各种类型子弹的行为)分离出来,独立封装成类(接口或者说是抽象类)(在魂斗罗中是指可以发射子弹)。某一类行为具有不同的实现方法(即可以发射棉花弹,散弹,直弹,火箭弹),这就组成了一组行为(就是定义中所讲到的算法族),这些行为之间是可以相互替代的(吃了不同的道具,就可以更换成不同类型的子弹)。

此模式让算法的变化独立于使用算法的客户:即在更换各种类型的子弹的时候,人这个主体并未发生改变。

利用到的设计原则:封装变化,针对接口编程,而非具体实现编程。

如果现在我再增加一个能够发射前后散弹的子弹类型,那么并不会改变类robots的任何代码,只需要增加一个类并继承shot即可。即松耦合原则。


6.代理模式


转载于:https://my.oschina.net/weiweiblog/blog/472751

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值