黑马程序员 设计模式

------- android培训java培训、期待与您交流! ----------

Java设计模式



一、概述

使用java中的设计模式可以增加程序的复用性,提高程序的健壮性等等。设计模式的初衷是为了给人提供方便,或为了达成某种目的而使用。在程序设计的时候我们要首先考虑到程序的要求,再考虑使用模式能否提高程序性能。为了使用模式而使用模式是本末倒置的行为。


二、设计模式的六大原则



1、开闭原则(Open Close Principle)



开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。


2、里氏代换原则(Liskov Substitution Principle)



里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科


3、依赖倒转原则(Dependence Inversion Principle)



这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。


4、接口隔离原则(Interface Segregation Principle)



这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。


5、迪米特法则(最少知道原则)(Demeter Principle)



为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。


6、合成复用原则(Composite Reuse Principle)



原则是尽量使用合成/聚合的方式,而不是使用继承。




三、常用设计模式



单例设计模式
单例设计模式保证了在JVM中一个类只能有一个实例对象,这样有很多好处,比如不用频繁创建新对象,毕竟可以节约内存。
在某些时候核心类的对象只能有一个对象的时候单例设计模式也能保证系统的平稳运行


下面是两种单例设计模式的例子


/*
 * 单例设计模式
 * 延迟加载:	1.定义1个私有的静态本类对象为空
 * 		2.私有化构造函数,这里可以自行设计
 * 		3.给出一个公有的静态方法可以获取本类对象,判断条件为本类对象为空
 * 		(这里因为不能直接建立本类对象,只能通过类调用静态函数来得到本类对象)
 * 
 * 非延迟加载:1.定义1个私有静态的类对象
 * 		2.私有化构造函数
 * 		3.给出一个公共的静态方法可以返回本类对象,即第一步的本类对象;
 * 
 * 
 * */


//延迟加载
class a_SingleDesign{
	private static a_SingleDesign s=null;
	private a_SingleDesign()
	{
		//私有化构造函数防止new对象
	}
	public static a_SingleDesign get_aSingle()
	{
		//加入双重判断锁保证了安全和效率
		if(s==null)
		{
			synchronized(a_SingleDesign.class)
			{
				if(s==null)
				{
					 s=new a_SingleDesign();
				}
			}
		}
		return s;
	}
	//-----------------以上为设计结果-----------------------//
	public void get_aResult()
	{
		System.out.println("单例设计成功");
	}
	
}




//非延迟加载
class b_SingleDesign{
	private static b_SingleDesign s=new b_SingleDesign();
	private b_SingleDesign()
	{
	}
	public static b_SingleDesign get_aSingle()
	{
		return s;
	}
	//-----------------以上为设计结果-----------------------//
	public void get_aResult()
	{
		System.out.println("单例设计成功");
	}
	
}






public class SingleDesign {


	public static void main(String[] args) {
		
		a_SingleDesign a1=a_SingleDesign.get_aSingle();
		a1.get_aResult();
		a_SingleDesign a2=a_SingleDesign.get_aSingle();
		a2.get_aResult();
		
		b_SingleDesign b1=b_SingleDesign.get_aSingle();
		b1.get_aResult();
		b_SingleDesign b2=b_SingleDesign.get_aSingle();
		b2.get_aResult();
		
	}


}




通过学习单例模式,我们可以看到:
很多程序在单线程下运行没有多少问题,但是在多线程下运行可能就会出现安全问题或者效率的降低。没有绝对完美的设计模式,只有在程序的使用中找到最合适的。


装饰设计模式
装饰设计模式,即在一个类原有的基础上实现更强的功能,或者提高这个类的使用效率。装饰模式比继承要灵活。避免了继承体系的臃肿,且降低了类与类之间的关系。装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强的功能,所以装饰类和被装饰的类通常都是属于一个体系。从继承结构转为组合结构,降低了耦合度。


在java.io包中的BufferWriter等带缓冲区的输入输出流就是使用了装饰设计模式,在借用了原输入输出流对象的情况下不仅可以实现原输入输出流的功能,而在本类中增加了一个缓冲区,避免了程序的反复读写,在BufferedReader和BufferedWriter中还提供了更新的ReadLine方法和WriteLine方法。


自定义一个带缓冲区的输入流,并且能实现读一行的方法


/*
需求:根据readLine方法原理,模拟BufferedReader写一个自己的MyBufferedReader
*/
import java.io.*;
//自定义缓冲类
class MyBufferedReader extends Reader
{
	private Reader r;//定义接收的流对象
	MyBufferedReader(Reader r)
	{
		this.r=r;
	}
	//自定义整行读取
	public String myReadLine()throws IOException
	{
		//创建一个容器,用来存储一行的字符
		StringBuilder sb =new StringBuilder();
		//一个字符一个字符读取
		for (int ch=0;(ch=r.read())!=-1 ; )
		{
			if(ch=='\r')//如果遇到换行符,则继续
				continue;
			if(ch=='\n')//如果遇到回车符,表示该行读取完毕
				return sb.toString();
			else
				sb.append((char)ch);//将该行的字符添加到容器
		}
		if(sb.length()!=0)//如果读取结束,容器中还有字符,则返回元素
			return sb.toString();
		return null;
	}


	//复写父类中的抽象方法
	public int read(char[] cbuf, int off, int len) throws IOException
	{
		return r.read(cbuf,off,len);
	}


	//复写父类的close方法
	public void close()throws IOException
	{
		r.close();
	}
}
//测试MyBufferedReader
class  MyBufferedReaderDemo
{
	public static void main(String[] args) 
	{
		MyBufferedReader mbr=null;
		try
		{
			mbr=new MyBufferedReader(new FileReader("BufferedCopyDemo.java"));
			for (String line=null;(line=mbr.myReadLine())!=null ; )
			{
				System.out.println(line);//显示效果
			}
		}
		catch (IOException e)
		{
			throw new RuntimeException("读取数据失败");
		}
		finally
		{
			try
			{
				if(mbr!=null)
					mbr.close();
			}
			catch (IOException e)
			{
				throw new RuntimeException("读取流关闭失败");
			}
		}	
	}
}



装饰设计模式避免了一个体系下的每个类需要实现更强功能的时候都要有一个继承的子类的问题,而是转而把这些更强功能整合,再需要使用增强功能的时候只要把原有对象传值就能实现。避免了体系的臃肿。


适配器模式
适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。首先,我们来看看类的适配器模式。


核心思想就是:有一个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 {  
  
    @Override  
    public void method2() {  
        System.out.println("this is the targetable method!");  
    }  
}  
Adapter类继承Source类,实现Targetable接口,下面是测试类:




public class AdapterTest {  
  
    public static void main(String[] args) {  
        Targetable target = new Adapter();  
        target.method1();  
        target.method2();  
    }  
} 
 


输出:


this is original method!
this is the targetable method!


这样Targetable接口的实现类就具有了Source类的功能。
对象适配器模式基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。


public class Wrapper implements Targetable {  
  
    private Source source;  
      
    public Wrapper(Source source){  
        super();  
        this.source = source;  
    }  
 
    public void method2() {  
        System.out.println("this is the targetable method!");  
    }  
  


    public void method1() {  
        source.method1();  
    }  
}  
测试类:


public class AdapterTest {  
  
    public static void main(String[] args) {  
        Source source = new Source();  
        Targetable target = new Wrapper(source);  
        target.method1();  
        target.method2();  
    }  
}  


第三种适配器模式是接口的适配器模式,在学习GUI的时候,事件监听的方法只要超过3种基本都会有一个实现类Adapter,这个类完全复写了接口中全部的抽象类,但是这个类中的内容主体全都是空。这样有一个好处,当一个类想要实现待适配的接口的功能的时候只要继承Adapter类,然后复写自己需要的功能即可。而不用实现待适配的接口实现接口中全部的方法,尽管只需要用到其中一个或几个方法。


public interface Targetable {  
  
    public void method1();  
   
    public void method2();
  
    public void method2();


    public void method2();
}  


public abstract Adapter implements Targetable {
	
    public void method1(){};  
   
    public void method2(){};
  
    public void method2(){};


    public void method2(){};


}
//只想实现接口中的一个或多个方法时,可以继承Adapter并复写需要的方法。
ublic class SourceSub extends Adapter {  
    public void method1(){  
        System.out.println("只使用了一个方法");  
    }  
}  
public class Test {  
  
    public static void main(String[] args) {  
        new  SourceSub().method1();
         
    }  
}  



版权声明:本文为baidu_25218715原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。