创建型模式共分五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。下面来一一介绍
简单工厂方法模式(普通、多个方法、多个静态方法)
/*定义一个通用接口,提供需要通用方法*/
public interface Sender {public void send();}
public class SmsSender implements Sender {
@Override
public void send() {
System.out.println("this is sms sender!");
}
}
public class MailSender implements Sender{
@Override
public void send() {
System.out.println("this is mailsender!");
}
}
/*定义一个工厂类,提供生产方法,有可能是一个,也可能是多个,甚至是静态的,让类把实例化推迟到子类*/
public class SendFactory {
public Sender produce(String type) {
if ("mail".equals(type)) {
return new MailSender();
} else if ("sms".equals(type)) {
return new SmsSender();
} else {
System.out.println("请输入正确的类型!");
return null;
}
}
}
/*测试*/
public class FactoryTest {
public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produce("sms");
sender.send();
}
}
抽象工厂模式
上面 的简单工厂模式会有一个问题,如果业务扩展,我们需要一个发送通知的功能,那么就需要修改工厂类代码,这也违反了闭包原则(不可修改)。
所以在这里引申出抽象工厂模式,创建一个工厂接口和创建多个工厂实现类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前
的代码。
/*Sender类和其子类都用上个例子的,新增一个发送通知*/
public class NoticeSender implements Sender{
@Override
public void send() {
System.out.println("this is noticeSender!");
}
}
/*提供创建工厂的接口*/
public interface CommonFactory {
public Sender produce();
}
public class SendSmsFactory implements CommonFactory {
@Override
public Sender produce() {
return new SmsSender();
}
}
public class SendMailFactory implements CommonFactory {
@Override
public Sender produce() {
return new MailSender();
}
}
public class SendNoticeFactory implements CommonFactory {
@Override
public Sender produce() {
return new NoticeSender();
}
}
public class FactoryTest {
public static void main(String[] args) {
CommonFactory factory = new SendNoticeFactory();
Sender sender = factory.produce();
sender.send();
}
}
当然也可以怎加产品种类,比如增加一个Reciver接口
public interface Reciver {
public void recive();
}
public class SmsReciver implements Reciver {
@Override
public void recive() {
System.out.println("this is SmsReciver!");
}
}
public class SmsSender implements Sender {
@Override
public void send() {
System.out.println("this is sms sender!");
}
}
public class NoticeReciver implements Reciver {
@Override
public void recive() {
System.out.println("this is NoticeReciver!");
}
}
//工厂类实现通用工厂接口就可以了,略..
区别: 1.工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。 2.工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。
3.工厂方法创建 "一种" 产品,他的着重点在于"怎么创建",也就是说如果你开发,你的大量代码很可能围绕着这种产品的构造,初始化这些细节上面。也因为如此,类似的产品之间有很多可以复用的特征,所以会和模版方法相随。
单例模式
我们在spring中应该有接触一个注解或者属性scope,它标注着这是一个单例bean,在一个spring容器中只有一个实例,与我们现在要说的单例模式还不同。单例模式是指在jvm中只有一个实例。那为什么要使用单例模式呢?我们知道,每创建一个实例,都在内存中有一定开销,如果反复的创建一个功能一样的实例,那不是很浪费?同样也会对GC有影响,也会存在安全问题。
public class Singleton {
/* 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载 */
private static Singleton instance = null;
/* 私有构造方法,防止被实例化 */
private Singleton() {
}
/* 静态工程方法,创建实例 */
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
public Object readResolve() {
return instance;
}
}
以上这段代码在多线程环境下可能会出问题,假如多个线程同时抢占getInstance()方法,就会存在创建多个实例的问题。加锁能解决问题,我们改动代码如下:
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
锁方法,性能上存在不足,继续修改
public static Singleton getInstance() {
if (instance == null) {
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
这样调用的时候不需要加锁,为空需要创建的时候才会加锁。但是有可能线程进入同步块分配内存赋值成员后实例化的时候线程就离开同步块,另一个线程进入发现对象不为空,返回就发生错误。
public class SingletonTest {
private static SingletonTest instance = null;
private SingletonTest() {
}
private static synchronized void syncInit() {
if (instance == null) {
instance = new SingletonTest();
}
}
public static SingletonTest getInstance() {
if (instance == null) {
syncInit();
}
return instance;
}
}
建造者模式
这个模式光看字面上意思就可以理解,用多个小对象建造一个大对象。
这里代码就不贴了,引用别人的一张图介绍吧。里面大概有几个角色:
1.产品类:通常是实现了模板方法模式,也就是有模板方法和基本方法,这里指的是item
2.抽象建造者:规范产品的组件,例子中只有具体建造者没有写它的抽象类
3.具体建造者:用于建造单一的具体的产品,例子中指的是MealBuild
4.导演类:负责安排已有模块的顺序,然后告诉build开始创建,例子中指的是BuildPatten
建造者模式与工厂模式的不同:
/*原型模式通用代码*/
public class PrototypeClass implements Cloneable{
//覆写父类Object方法
@Override
public PrototypeClass clone(){
PrototypeClass prototypeClass = null;
try {
prototypeClass = (PrototypeClass)super.clone();
} catch (CloneNotSupportedException e) {
//异常处理
}
return prototypeClass;
}
}
需要注意的时,重写父类的clone方法是浅拷贝,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的;还有一种深拷贝,连引用类型也会重新创建,相当于全部重建,其实现方法也比较简单,采用流的形式读入当前对象的二进制输入,再写出二进制数据对应的对象。下面来举个原型模式的例子:
public abstract class Shape implements Cloneable{
private String id;
protected String type;
abstract void draw();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Rectangle extends Shape {
public Rectangle() {
type = "Rectangle";
}
@Override
void draw() {
System.out.println("this is Rectangle's draw method");
}
}
public class ShapeCache {
private static Hashtable shapeMap = new Hashtable();
/**
* 返回克隆对象
* @param shapeId
* @return
* @throws CloneNotSupportedException
*/
public static Shape getShape(String shapeId) throws CloneNotSupportedException {
Shape cachedShape = shapeMap.get(shapeId);
return (Shape) cachedShape.clone();
}
public static void loadCache() {
//假设从数据库取,消耗较大
Rectangle rectangle = new Rectangle();
rectangle.setId("3");
shapeMap.put(rectangle.getId(),rectangle);
}
}
//调用
public class PrototypePatternDemo {
public static void main(String[] args) throws CloneNotSupportedException {
ShapeCache.loadCache();
Shape clonedShape = (Shape) ShapeCache.getShape("3");
System.out.println("Shape : " + clonedShape.getType());
}
}
好了,来总结一下。我们讲到了五个模式,工厂模式主要是创建,在乎结果,不在乎方法执行的顺序,建造者模式则在乎方法执行顺序,顺序不一样构造出来的对象也是不同的,单例模式则是为了在jvm中只有一个实例,保证了性能及安全,原型模式则是为了避免过多的创建而使用拷贝,用拷贝对象的方法减少资源的消耗。