欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

由浅入深,带你玩转几种常用java设计模式

程序员文章站 2022-07-11 11:59:30
...

 

PART A:前言

平常我们都在敲代码,为了要实现一些我们希望看到的功能,敲一大堆一大堆。往往就会忽略了这样的一个问题。

你会问敲代码就让我们老老实实的敲代码吧,为什么要那么麻烦的去考虑那么多?当然了现在这样一说你肯定会回答我们肯定不可能就一心只会死头死脑的无脑敲代码啊。是吧?那么我们还要考虑一些什么事情呢?这么跟大家说吧,我们现在敲代码做项目就像做房子,现在我们做的事情是,一块一块的不断的垒砖块,无脑垒。而不管他垒的好不好看美不美观,也不管他消耗的砖块是否太多。是不是?再打个比方,从小学起我们就开始拿着笔写作文。刚刚开始那个时候,还记得自己是怎么写作文的么?是不是照着课本写?又或者就是写一些流水账似的东西?记得那个时候能够记两笔流水账已经能够让自己激动不已了是吧?呵呵。那你还记得是从什么时候开始,老师开始给你讲文章的结构文章的排篇布局,开始给你介绍各种诸如开门见山等等的文章写法的?今天就让我们回到那个时候。

接下来我们开始接触一些比较常用的java设计模式。

 

PART B

         B-1工厂模式

你可以从网上找到许许多多关于这个(java设计模式)的文档与资料,如果你下载过看过不止四五份你就会发现,虽然他们的说法都有自己的一套,但是总是有千人一面的地方。而我要告诉你的是,这一面,就是你所需要的东西了。

对于工厂模式而言,每个人都会有自己的体会与看法。就比如有的人说他是将代码按照其功能模块化了,也有人说他就是一个分配机制,好比把不同的工作交给不同的人去做一样,将对象的功能的实现交给一些特制的类去完成,等等等等。只要是接触过的人,就可以说出一种他的立场上看到的工厂模式。

但是在这里我要告诉你的是,工厂模式他的关键是:将创建对象和使用对象分开。在这样的一个过程中不仅仅达到了理清编写者自己思路的作用,也使得代码脉络更加清晰明朗,简洁易懂。不知道大家还记不记得曾经讲哈夫曼树的时候那棵充斥我们一个多礼拜的哈夫曼树?我想说,现在这棵树是没了,但是重新出现了一座庞大的工厂……在这个工厂里边分工明确权责分明,他的每一个子工厂都只负责生产某一种特别的产品,而每一种产品也对应着每一个子工厂的生产线。现在只要想编写一个程序,就不知道绝的先考虑将它“工厂化”,将它的每一个步骤每一个功能先大卸八块的区分清楚,然后才开始代码的实际编写工作……

好了,闲话就不多说了,下面我们就通过实例来讲讲什么是创建对象和使用对象分开。

(例)

比如我想造一辆宝马车并让它跑起来,以前我们都是写一个宝马车的类然后直接在这个类里边实例化一个他的对象,完了以后紧接着在下边写宝马车的跑的方法,是吧?但是工厂模式不这么做,工厂模式怎么做呢?请看下面的步骤:

1.写一个车的接口,并在里边定义一个车的go()方法:

 

public interface Car {
	public void go();
}

 2.写一个宝马车的类,让他去继承上面这个车的总接口,并且实现里边的方法:

 

public class BMW implements Car{
	public void go() {
	}
}

 3.是不是少了什么?呵呵你有车的接口和实现类了当然得有造车工厂咯,是吧?于是我们同样给它定义一个造车工厂总接口以及一个继承并且实现它的宝马造车工厂:

 

public interface CarFactory {
	public Car build(String name) ;
}
 

 

public class BMWFactory implements CarFactory{
	
 private static  BMWFactory ins;
	 
	 public static BMWFactory getIns(){
		 if(null==ins){
			 ins=new BMWFactory();
		 }
		 return ins;
	 }
	 
	 BMWFactory(){}
	 
	
	public Car build(String name) {
		
		 if(name.equals("BMW")){
			
			 return new BMW();
		 }
		
		return null;
	}

}

 4.有的人就会有点牢骚了,我不想老是自己跑工厂去,那样多麻烦!是吧?好,那么我们就给他写一个且车代理商:

 

public class AgentFactor {
	private static AgentFactor ins;
	public static AgentFactor getIns(){
		if(ins==null){
			ins=new AgentFactor();
		}
		return ins;
	}
	
	//取得制定品牌 的汽车
	public CarFactory getCarFactor(String Name){
		if(Name.equals("BMW")){
			return new BMWFactory();
		}
		return null;
	}
}

5.好了,车有了,造车工厂有了,连代理商都给你搞定了,那么就让我们来写个主函数让我们的宝马车跑起来吧!

 

public class CarTest {
	public void driver(){
		
		CarFactory ic=AgentFactor.getIns().getCarFactor("BMW");
		Car mini=ic.build("MINI");
		mini.go();
	}
}

 当然了,也不是真的就让上面的代码跑起来,细心如你,肯定会发现上面的这几行代码是跑不起来的,是不是?具体是为什么呢,哈哈就留给你咯!

虽然上面给大家的几行代码不能够直接跑起来,但是通过他们,我想大家对于工厂模式这个概念应该会有一个比较清晰的把握了吧。再次说一遍:工厂模式,就是将对象的创建与使用分开。这样做的目的,自己开动脑经咯~

 

B-2 事件监听模式

相信大家接触java以来就一直在跟鼠标监听器等等各种事件监听器打交道,对于这些个零零总总的各式各样的监听器也并不陌生吧?但是对于这些鼠标监听器啊键盘监听器啊什么的,他的具体的实现方式是怎么样的你是否清楚呢?如果你是一个足够细心而好学的人,那么我接下来要说的东西对你来说可能是没什么必要的了,因为你肯定看过这些监听器它的源码,也必然知道他的运行机制与原理了。

下面让我们用代码实例来看一看这事件监听的原型吧!

(例)在做通信的时候我们曾经做过收到消息并且让他显示在一个JTEXTAREA上面,但是若我想要让他显示在JLABEL上的话就得对代码进行一些联动的改动,很是麻烦。我们且看事件监听模式怎么解决这个问题:

1.写一个消息的接口,在里边定义几项消息的基本属性:

 

//定义一个消息接口,所有的消息都是他的实现类
public interface Msg {
	public byte getType();//返回消息类型
	public String getText();//返回消息内容
}

 2.写一个具体的消息类,继承消息接口:

 

public class TextMsg implements Msg{
	private String text;
	//具体的消息类,继承消息接口
	public TextMsg(String text){
		this.text=text;
	}
	public String getText() {
		
		return this.text;
	}
public byte getType() {
		return 2;
	}

}

 3.第三布我们要做的是,编写一个监听器接口:

 

//处理器接口定义
public interface MsgProcess {
	//具体的处理器,所有的处理器实现类都必须实现这个方法
	 void processMsg(Msg msg);
}

 4.编写你需要的监听器,比如你想让消息呈现在JLABEL上:

 

import javax.swing.JLabel;

public class JLabelProcess extends JLabel implements MsgProcess{
	public void processMsg(Msg msg) {
		String t=msg.getText();

		this.setText(t);
		
		System.out.println(t);
	}
}

如果你还想让消息显示在其他地方,比如,JBUTTON上,你可以另外写一个监听器的类继承上面的监听器接口: 

 

import javax.swing.JButton;

public class JButtonProcess extends JButton implements MsgProcess{
	public void processMsg(Msg msg) {
		String t=msg.getText();
		this.setText(t);
	}
}

 5.编写一个线程,我们将模拟生成消息(事件源)放在这个线程里边来做:

 

public class NetConn extends Thread{
	
	//保存事件监听器的队列
	ArrayList<MsgProcess>  ips=new ArrayList<MsgProcess>();
	
	public void addMsgProcess(MsgProcess p){
		ips.add(p);
	}
	
	public void run(){
		//模拟事件源
		int i=0;
		while(true){
			
			Msg s=new TextMsg("我收到的消息是:"+i);
			i++;
			for(int t=0;t<ips.size();t++){
				MsgProcess pro=ips.get(t);
				pro.processMsg(s);
			}
			try {
				this.sleep(1000);
			} catch (InterruptedException e) {e.printStackTrace();}
		}
	}
	
	
}

 6.好的,做完了上面的这些工作,接下来就让我们来写一个主函数吧:

 

import java.awt.FlowLayout;
import javax.swing.JFrame;

public class Main {
	public static void main(String srga[]){
		NetConn nc=new NetConn();
		nc.start();
		
		JLabelProcess lp=new JLabelProcess();
		nc.addMsgProcess(lp);
		JButtonProcess tp=new JButtonProcess();
		nc.addMsgProcess(tp);
		
		JFrame jf=new JFrame("test");
		
		jf.add(tp);
		
		jf.setSize(300,300);
		jf.setLayout(new FlowLayout());
		jf.add(lp);
		jf.setVisible(true);
		jf.setDefaultCloseOperation(3);
	}
}

 事件监听模式介绍到这里你是不是心里隐隐感觉,这个世界上的好多事情都变成了一个个事件源和一个个监听处理器了?如果对于事件监听模式还有一些不解或者困惑,请细心看上面提供的代码示例,慢慢体会它里边所蕴含的一些东西,相信你会获得意想不到的收获的!

 

B-3单例模式

好了,说完了两种比较罗嗦一点的工厂和事件监听模式,下面让我们来看看一种比较简单的java设计模式:单例模式。对于单例模式我想我不用说大家也能够说出这种模式就是实现单实例的,没错,就是如此!

单例就是:保证一个类仅有一个实例,仅提供一个访问它的全局访问点。

 

他的适用性在于:

 1.当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。

 2.当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。

话不多说,请君看我代码示例:

 

public class Singleton {
    
    private static Singleton sing;

    private Singleton() {
        
    }
    
    public static Singleton getInstance() {
        if (sing == null) {
            sing = new Singleton();
        }
        return sing;
    }
}

 public class Test {

    
    public static void main(String[] args) {
        Singleton sing = Singleton.getInstance();
        Singleton sing2 = Singleton.getInstance();
        
        System.out.println(sing);
        System.out.println(sing2);
    }
}

 

 

ok,今天就介绍到这儿,这三种基本的java设计模式平时用的很多,当然,设计模式还有很多,由于时间关系我们在这里不便罗嗦太多,你可以自己去了解去学习去运用。但是要记住一点,不管是什么模式,他的实用性都体现在大型项目或者一些代码量很大的项目上。当你敲的代码足够多了,你就自然会对这些设计模式的作用和意义有一个深刻全面的体会。不管是工厂模式还是事件监听模式,又或者甚至是单例模式,他们的光芒都要在无数行代码之上才能够足够彰显足够耀眼。