初学者对Java设计模式的认识(一)

1.学习的作用

初学者的话,建议经常看一看设计模式,有利于代码的理解和书写。
我认为java设计模式最大的作用就是对代码的理解和对底层开发的认识,很多像spring、tomcat、springmvc等等都是用到了java的设计模式,而且如果理解透彻,对代码的封装、类的解耦有很大的帮助。

2.设计模式的六大原则

2.1开闭原则

在应用需求改变时,在不修改软件实体的源代码的前提下,能够扩展模块的功能,使其满足新的需求。
对测试人员来讲,只需要测试扩展的代码即可。提高代码的可复用性。

2.2里氏代换原则

官方大概的解释就是,LSP必须满足基类与子类的关系才能够存在。任何一个基类出现的地方,子类一定可以出现。基类是抽象,子类是具体。

2.3依赖倒转原则

上层模块不依赖下层模块,两者都应该依赖抽象;抽象不依赖具体,但具体依赖抽象。其核心思想就是面向接口编程。
实现开闭原则的重要途经之一,降低客户与实现模块之间的耦合。

2.4接口隔离原则

将庞大的接口拆分称小的具体的接口,每个类都建立其他们需要的专用接口。
提高类的内聚性、降低他们之间的耦合性,提高系统的灵活性和可维护性。

2.5迪米特法则

一个实体尽量减少和其他实体之间发生相互作用,可以通过第三方转发调用。其目的是降低类之间的耦合度,提高系统功能模块之间相对独立性。

2.6合成复用原则

在软件复用时。尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承实现。如果使用继承关系,必须严格遵循里氏代换原则。

3.创建型模式

主要是将对象的创建与使用分离。降低系统的耦合度,使用者不需要关注对象的创建细节,对象的创建由相关的工厂来完成。

3.1.工厂方法模式

定义一个用于创建产品的接口,其每个子类可以生成一系列的相关产品。
分为(普通工厂模式、多个工厂方法模式、静态工厂方法模式)

3.1.1普通工厂模式

就是建立一个工厂类,对实现了同一个接口的一些类进行实例的创建。

public interface Animal {
	public void say();
}
public class Dog implements Animal{
	public void say() {
		System.out.println("汪汪");
	}
}
public class Cat implements Animal{
	public void say() {
		System.out.println("喵喵");
	}
}
public class AnimalFactory {
	public Animal produce(String animal) {
		if("cat".equals(animal)) return new Cat();
		else if ("dog".equals(animal)) return new Dog();
		else return null;
	}
}
public class FactoryTest {
	public static void main(String []args) {
		AnimalFactory animalFactory = new AnimalFactory();
		Animal animal = animalFactory.produce("dog");
		animal.say(); //输出"汪汪"
	}
}

3.1.2多个工厂方法模式

对普通工厂方法模式的改进,防止因传递字符串出错而不能正确创建对象。

//修改创建工厂类
public class AnimalFactory {
	public Animal produceCat() {
		return new Cat();
	}
	public Animal produceDog() {
		 return new Dog();
	}
}
public class FactoryTest {
	public static void main(String []args) {
		AnimalFactory animalFactory = new AnimalFactory();
		Animal animal = animalFactory.produceCat();
		animal.say();//输出"喵喵"
	}
}

3.1.3静态工厂方法模式

将创建工厂类里面的方法设置为静态,不需要创建实例,直接通过类调用即可。

	public class AnimalFactory {
	public static Animal produceCat() {
		return new Cat();
	}
	public static Animal produceDog() {
		 return new Dog();
	}
}
public class FactoryTest {
	public static void main(String []args) {
		Animal animal = AnimalFactory.produceDog();
		animal.say(); //输出"汪汪"
	}
}

3.2抽象工厂模式

工厂方法模式,类的创建依赖工厂类,如果要拓展,必须对工厂类进行添加修改,这违背了闭包原则。所以抽象工厂模式解决了此问题,创建多个工厂类,这样一旦拓展,只需要添加工厂类即可,不需要修改之前的代码。

//Animal、Dog、Cat类和上面工厂方法模式的代码不变
public interface AnimalFactory {
	public Animal produce();
}
public class DogFactory implements AnimalFactory{
	public Animal produce() {
		return new Dog();
	}
}
public class CatFactory implements AnimalFactory{
	public Animal produce() {
		return new Cat();
	}
}
public class FactoryTest {
	public static void main(String []args) {
		AnimalFactory factory = new DogFactory();
		Animal animal = factory.produce();
		animal.say(); //输出"汪汪"
	}
}

3.3单例模式

在java应用中,单例对象能保证在一个jvm中只存在一个实例。这样减少类的创建可以减少系统的开销减少GC压力。
单例模式分类:饿汉式、单线程写法、多线程写法、多线程安全效率写法、静态内部类写法、枚举写法。

3.3.1饿汉式

类加载时就完成初始化,所以类加载较慢,但获取对象的速度快

public class Singleton {
	private static Singleton singleton = new Singleton();
	private Singleton() {}
	public Singleton getInstance() {
		return singleton;
	}	
}

3.3.2单线程写法

这种方式可以延迟类的加载速度,能够满足基本的需求。

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

3.3.3多线程写法

相比单线程写法,这种写法在多线程的情况下安全多了,但是也不能够保证没问题。因为instance = new Singleton();是分两步执行的,在jvm中不能够保证这两部操作的先后顺序,如果是先给Singleton分配空间(此时已经跳出synchronized),然后再赋值初始化,那就出错了。

public class Singleton {
	private static Singleton instance;
	private Singleton() {
	}
	public static Singleton getInstance() {
		if(instance == null) { 
			synchronized (instance) {
				if(instance == null)
					instance = new Singleton();
			}
		}
		return instance;
	}
}

3.3.4静态内部类写法

相比多线程写法,此写法,再jvm内部机制中能够保证当一个类被加载时,这个类的加载过程时线程互斥的。这样当我们调用getInstance时,jvm能够帮我们保证instance只创建一次。

public class Singleton {
	private Singleton() {
	}
	private static class SingletonFactory {
		private static Singleton instance = new Singleton();;
	}
	public static Singleton getInstance() {
		return SingletonFactory.instance;
	}
}

3.3.5枚举写法

最佳的单例实现模式就是枚举模式,利用枚举的特性,让jvm来帮我们保证线程安全和单一实例的问题

public enum Singleton {
	INSTANCE;
	public void say() {
		System.out.println("汪汪");
	}
}

学到这里肯定有人问为什么不直接使用static修饰类去加载呢。因为单例可以被延迟初始话,静态类第一次加载就是初始化,如果系统庞大,在性能方面是个很大的考验。

3.4建造者模式

建造者模式就是将一个复杂对象的构造与它的表示分离,使同样的构造过程可以创建不同的表示。它是将一个复杂的对象分解为多个简单的对象,然后一步步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分时可以灵活选择的。
建造者模式由产品、抽象建造者、具体建造者、指挥者4个要素构成。

//产品
public class Product {
	private String partA;
	private String partB;
	private String partC;
	public void setPartA(String partA) {
		this.partA = partA;
	}
	public void setPartB(String partB) {
		this.partB = partB;
	}
	public void setPartC(String partC) {
		this.partC = partC;
	}
	public void show() {
		System.out.println("partA:"+partA+"partB:"+partB+"partC:"+partC);
	}
}
//抽象建造者
public abstract class Builder {
	protected Product product = new Product();
	public abstract void buildPartA();
	public abstract void buildPartB();
	public abstract void buildPartC();
	public Product getResult() {
		return product;
	}
}
//具体建造者(可以定义多个,这里只是测试用了一个)
public class BuilderA extends Builder{
	public void buildPartA() {
		product.setPartA("建造partA---1");
	}
	public void buildPartB() {
		product.setPartB("建造partB---1");
	}
	public void buildPartC() {
		product.setPartC("建造partC---1");
	}
}
//指挥者
public class Director {
	private Builder builder;
	
	public Director(Builder builder) {
		this.builder = builder;
	}
	public Product construct() {
		builder.buildPartA();
		builder.buildPartB();
		builder.buildPartC();
		return builder.getResult();
	}
}
public class Client {
	public static void main(String []args) {
		Builder builder = new BuilderA();
		Director director = new Director(builder);
		Product product = director.construct();
		product.show();//输出"partA:建造partA---1partB:建造partB---1partC:建造partC---1"
	}
}

3.5原型模式

用一个已经创建的实例作为原型,通过复制来创建一个和原型相同或相似的新对象。原型模式的克隆分为浅克隆和深克隆。

//浅克隆
public class Cat implements Cloneable{
	private Integer age;
	public Cat clone() throws CloneNotSupportedException {
		Cat cat = (Cat)super.clone();
		return cat;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}
public class Client {
	public static void main(String []args) {
		Cat cat1 =new Cat();
		cat1.setAge(20);
		try {
			Cat cat2 = (Cat)cat1.clone();
			System.out.println(cat1.getAge());//输出“20”
			System.out.println(cat2.getAge());//输出“20”
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

浅克隆:将一个对象复制后,基本数据类型的变量都会重新创建,但是引用类型,指向还是原来对象的指向。

深克隆:将一个对象复制后,基本数据类型和引用类型都被重新创建。完全彻底的复制。

public class Cat implements Cloneable,Serializable{
	private Integer age;
	public Object deepClone()throws IOException,ClassNotFoundException{
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(this);
		
		ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bis);
		return ois.readObject();
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
}
public class Client {
	public static void main(String []args) {
		Cat cat1 =new Cat();
		cat1.setAge(20);
			Cat cat2;
			try {
				cat2 = (Cat)cat1.deepClone();
				System.out.println(cat1.getAge());
				System.out.println(cat2.getAge());
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值