设计模式学习--创建型

工厂方法(Factory Method)

普通工厂模式

创建一个工厂类,对实现了同一个接口的一些类进行实例的创建。客户端传入不同的字符串,创建不同的实例。

接口:

package FactoryMethod;

 

public interface Sender {

    public void Send();

}

 

实现类:

//mail

package FactoryMethod;

 

public class MailSender implements Sender {

    @Override

    public void Send() {

        System.out.println("this is mailsender!");

    }

}

 

//sms

package FactoryMethod;

 

public class SmsSender implements Sender {

 

    @Override

    public void Send() {

        System.out.println("this is sms sender!");

    }

}

 

工厂类:

package FactoryMethod;

 

public class SendFactorySimple {

 

    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;

        }

    }

}

 

客户端:

package FactoryMethod;

 

public class client {

 

    public static void main(String[] args) {

        SendFactorySimple factory = new SendFactorySimple();

        Sender sender = factory.produce("sms");

        sender.Send();

    }

}

 

多个工厂方法模式

提供多个工厂方法,分别创建对象。

工厂类:

package FactoryMethod;

 

public class SendFactoryMultiple {

   

    public Sender produceMail(){

        return new MailSender();

    }

   

    public Sender produceSms(){

        return new SmsSender();

    }

}

 

客户端:

package FactoryMethod;

 

public class client {

 

    public static void main(String[] args) {       

        SendFactoryMultiple factoryM = new SendFactoryMultiple();

        Sender senderM = factoryM.produceMail();

        senderM.Send();

    }

}

静态工厂方法

多个工厂方法模式里面的方法设置为静态,不需要创建实例,直接调用。

工厂类:

package FactoryMethod;

 

public class SendFactoryStatic {

   

    public static Sender produceMail(){

        return new MailSender();

    }

   

    public static Sender produceSms(){

        return new SmsSender();

    }

}

 

客户端:

package FactoryMethod;

 

public class client {

 

    public static void main(String[] args) {

        Sender senderS = SendFactoryStatic.produceMail();

        senderS.Send();

    }

}

总结

总体来说,工厂模式适合:凡是出现了大量的产品需要创建,并且具有共同的接口时,可以通过工厂方法模式进行创建。在以上的三种模式中,第一种如果传入的字符串有误,不能正确创建对象,第三种相对于第二种,不需要实例化工厂类,所以,大多数情况下,我们会选用第三种——静态工厂方法模式。

抽象工厂(Abstract Factory)

把工厂抽象出来,不同的工厂生产不同的产品。这样做,一旦需要增加新的功能,直接增加新的工厂类,不需要修改之前的代码。

接口:

package AbstractFactory;

 

public interface Sender {

    public void Send();

}

 

实现类:

//Mail

package AbstractFactory;

 

public class MailSender implements Sender {

 

    @Override

    public void Send() {

        // TODO Auto-generated method stub

        System.out.println("This is mailsender...");

    }

 

}

//sms

package AbstractFactory;

 

public class SmsSender implements Sender {

 

    @Override

    public void Send() {

        // TODO Auto-generated method stub

        System.out.println("This is sms sender...");

    }

 

}

 

 

工厂接口:

package AbstractFactory;

 

public interface producer {

    public Sender produce();

 

}

 

 

 

工厂实现类:

//mail

package AbstractFactory;

 

public class SendMailFactory implements producer {

 

    @Override

    public Sender produce() {

        // TODO Auto-generated method stub

        return new MailSender();

    }

 

}

 

//sms

package AbstractFactory;

 

public class SendSmsFactory implements producer {

 

    @Override

    public Sender produce() {

        // TODO Auto-generated method stub

        return new SmsSender();

    }

 

}

 

 

测试类:

package AbstractFactory;

 

public class client {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        producer Producer = new SendMailFactory();

        Sender sender = Producer.produce();

        sender.Send();

       

    }

 

}

 

 

总结

这个模式的好处就是,如果你现在想增加一个功能:发及时信息,则只需做一个实现类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。这样做,拓展性较好!

建造者(Builder)

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理。

接口:

package Builder;

 

public interface Sender {

    public void send();

}

 

实现类:

//sms

package Builder;

 

public class SmsSend implements Sender {

 

    @Override

    public void send() {

        // TODO Auto-generated method stub

        System.out.println("Sms...");

    }

 

}

 

//Email

package Builder;

 

public class EmailSender implements Sender {

 

    @Override

    public void send() {

        // TODO Auto-generated method stub

        System.out.println("Email...");

    }

 

}

 

 

建造者类:

package Builder;

 

import java.util.List;

import java.util.ArrayList;

 

public class Builder {

    private List<Sender> SenderList = new ArrayList<Sender>();

   

    public List<Sender> getList(){

        return SenderList;

    }

   

    public void BuildSmsSender(int counter){

        for(int i=1; i<=counter; i++){

            SenderList.add(new SmsSend());

        }

    }

   

    public void BuildEmailSender(int counter){

        for(int i=1; i<=counter; i++){

            SenderList.add(new EmailSender());

        }

    }

}

 

 

测试类:

package Builder;

 

import java.util.List;

 

public class Client {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        Builder builder = new Builder();

        builder.BuildEmailSender(3);

        builder.BuildSmsSender(3);

        builder.BuildEmailSender(3);

       

        List<Sender> list = builder.getList();

        for(int i=0; i<list.size(); i++) {

            System.out.println(i);

            Sender sender = list.get(i);

            sender.send();

        }

       

    }

 

}

 

总结

建造者模式将很多功能集成到一个类里,这个类可以创造出比较复杂的东西。所以与工厂模式的区别就是:工厂模式关注的是创建单个产品,而建造者模式则关注创建复合对象,多个部分

原型模式(Prototype)

将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象。分为浅复制和深复制两种。

浅复制

Clone()

第一:Object类的clone()方法是一个native方法,native方法的效率一般来说都是远高于Java中的非native方法。

第二:Object类中的 clone()方法被protected修饰符修饰:需要重载clone()方法,并将属性值设为public。

第三:Object.clone()方法返回一个Object对象:需要强制类型转换。

Clonable

Cloneable接口仅仅是一个标志,而且这个标志也仅仅是针对 Object类中 clone()方法的,如果 clone 类没有实现 Cloneable 接口,并调用了 Object  clone() 方法(也就是调用了 super.Clone() 方法),那么Object  clone() 方法就会抛出 CloneNotSupportedException 异常。

浅复制原型模式

一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称。将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

原型类:

package Prototype;

 

public class Prototype implements Cloneable {

    private int age;

    private int[] array = new int[] {1,2,3};

    public Prototype() {

    }

    public Prototype(int age) {

        this.age = age;

    }

    public int getAge(){

        return age;

    }

    public void setAge(int age){

        this.age = age;

    }

    public int[] getArray(){

        return array;

    }

    public void setArray(int[] array){

        this.array = array;

    }

    protected Object cloneObject() throws CloneNotSupportedException{

        Prototype prototype = (Prototype) super.clone();

        return prototype;

    }

}

 

 

测试类:

package Prototype;

 

public class client {

 

    /**

     * @param args

     * @throws CloneNotSupportedException

     */

    public static void main(String[] args) throws CloneNotSupportedException {

        // TODO Auto-generated method stub

        Prototype prototype = new Prototype(20);

        Prototype cloneProto = (Prototype)prototype.cloneObject();

       

        /*

         * 地址不同说明完成复制

         */

        System.out.println("prototype = " + prototype); 

        System.out.println("cloneProto = " + cloneProto);

            

        /*

         * 地址相同,说明复制不完全

         */

        System.out.println("prototype.getArray() = " + prototype.getArray()); 

        System.out.println("cloneProto.getArray() = " + cloneProto.getArray());

       

        /*

         * 改变array中的值测试

         */

        int[] temp = prototype.getArray();

        for(int i=0; i<temp.length; i++){

        System.out.println(temp[i]);

        }

        temp = cloneProto.getArray();

        for(int i=0; i<temp.length; i++){

        System.out.println(temp[i]);

        }

       

        cloneProto.setArrayElem(100);

       

        temp = prototype.getArray();

        for(int i=0; i<temp.length; i++){

        System.out.println(temp[i]);

        }

        temp = cloneProto.getArray();

        for(int i=0; i<temp.length; i++){

        System.out.println(temp[i]);

        }

       

    }

 

}

 

深复制

在Java语言里深层复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流中,再从流中读出来,便可以重建对象。这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象是否设成transient,从而将之排除在复制过程之外。

序列化

广义上的序列化指将内存中的各种数据(文本、图片、语音、视频等)通过一定策略转换成字节序列的形式,方便保存到数据库或硬盘,或者进行网络数据通信。而反序列化就是将序列化后的字节序列恢复为原来的数据。

   在Java中,把Java对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为Java对象的过程称为对象的反序列化。

两种用途:

   ①把对象的字节序列保存在硬盘(通常是一个文件)或数据库中;

   ②在网络上传送对象的字节序列。

注:能否反序列化仅以serialVersionUID 为标识,找不到的元素为null.

序列化允许重构

序列化允许一定数量的类变种,甚至重构之后也是如此,ObjectInputStream 仍可以很好地将其读出来。

Java Object Serialization 规范可以自动管理的关键任务是:

将新字段添加到类中

将字段从 static 改为非 static

将字段从 transient 改为非 transient

取决于所需的向后兼容程度,转换字段形式(从非 static 转换为 static 或从非 transient 转换为 transient)或者删除字段需要额外的消息传递。

serialVersionUID

If you're actually using serialization, it only matters if you plan on storing and retrieving objects using serialization directly. The serialVersionUID represents your class version, and you should increment it if the current version of your class is not backwards compatible with its previous version.

序列化API

1. 对象输出流java.io.ObjectOutputStream它的void writeObject(Object obj)方法可对参数obj对象进行序列化,将得到的字节序列输出到一个目标输出流(创建ObjectOutputStream时指定)中。

2. 对象输入流java.io.ObjectInputStream它的Object readObject()方法从一个源输入流(创建ObjectInputStream时指定)中读取字节序列,再把它们反序列化成一个对象,并将其返回。

3. 序列化相关接口:实现了Serializable或Externalizable接口的类被称为可序列化类。只有可序列化类才能被序列化,否则ObjectOutputStream的writeObject(Object obj)方法会抛出IOException。

实现Serializable接口的类可以采用默认的序列化方式。

实现Externalizable接口的类完全由自身控制序列化的行为。

序列化步骤

1)对象序列化

① 创建一个ObjectOutputStream,它包装一个其他类型的目标输出流,如文件输出流FileOutputStream;

② 通过ObjectOutputStream的writeObject()方法进行序列化,写到目标输出流。

2)对象反序列化

① 创建一个ObjectInputStream,它包装一个其他类型的目标输入流,如文件输入流FileInputStream;

② 通过ObjectInputStream的readObject()方法进行反序列化,读取对象并返回。

JAVA流与文件

1. 阻塞:read 和 write方法在执行时都将阻塞,直至字节确实被读入或者写出。这就意味着如果留不能够立即被访问,那么当前线程将被阻塞。

available方法防止阻塞:

int bytesAvailable = in.available();

if (bytesAvailable){

    byte[] data = new byte[bytesAvailable];

    in.read(data);

}

2. 组合过滤器

FileInputStream和FileOutputStream可以提供附着在一个磁盘文件上的输入流和输出流,只需要提供文件名或者完整路径名。

FileInputStream fis = new FileInputStream("catDemo.out");

与抽象类InputStream和OutputStream一样,这些类支持在字节级别上的读写,也就是说只能从fis对象中读入字节和字节数组。DataInputStream只能读入数字类型,却没有任何从文件中获取数据的方法。Java使用一种灵巧的机制来分离这两种职责。

为了从文件中读入数字,首先需要创建一个FileInputStream,然后将其传递给DataInputStream的构造器。

FileInputStream fin = new FileInputStream("employee.dat");

DataInputStream din = new DataInputStream(fin);

double s = din.readDouble();

流在默认情况是不被缓冲期缓存的,也就是说,每个对read的调用都会请求操作系统再转发一个字节、相比之下,请求一个数据块并将其置于缓冲区中会显得更加高效。

DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream("employee.dat")));

3. FileOutputStream

FileOutputStream(String name, boolean append);

ByteArrayInputStream

public class ByteArrayOutputStream  extends OutputStream

此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray()和 toString()获取数据。

关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何IOException。

深复制原型模式

将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。用到对象序列化,采用二进制流的形式完成对对象的读写。

原型类:

package Prototype;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.io.Serializable;

 

public class PrototypeDeep implements Serializable {

         private static final long serialVersionUID = 1L;

         private int age;

         private int[] array = new int[] {1,2,3};

                  

         public PrototypeDeep(){

                  

         }

         public PrototypeDeep(int age){

                   this.age = age;

         }       

         public int getAge(){

                   return this.age;

         }

         public void setAge(int age){

                   this.age = age;

         }

         public int[] getArray() {

                   return this.array;

         }

         public void setArray(int[] array){

                   this.array = array;

         }

         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();

                  

         }

        

}

 

 

测试类:

package Prototype;

 

import java.io.IOException;

 

public class client {

 

    public static void main(String[] args) throws ClassNotFoundException,

            IOException {

 

        PrototypeDeep prototypeDeep = new PrototypeDeep(20);

        PrototypeDeep clonePrototypeDeep = (PrototypeDeep) prototypeDeep

                .deepClone();

        /*

         * 地址不同说明完成复制

         */

        System.out.println("prototypeDeep = " + prototypeDeep);

        System.out.println("clonePrototypeDeep = " + clonePrototypeDeep);

 

        /*

         * 地址相同,说明复制不完全

         */

        System.out

                .println("prototypeDeep.getArray() = " + prototypeDeep.getArray());

        System.out.println("clonePrototypeDeep.getArray() = "

                + clonePrototypeDeep.getArray());

       

        int[] proArray = prototypeDeep.getArray(); 

        int[] cloneProtoArray = clonePrototypeDeep.getArray(); 

        for (int p : proArray) { 

            System.out.print(p + "\t"); 

        } 

        System.out.println(); 

        for (int p : cloneProtoArray) { 

            System.out.print(p + "\t"); 

        }

    }

}

 

 

单例模式 (Singleton)

一种常用的设计模式。在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。

好处主要有:

1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。

2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。

单例模式主要有两种实现方式:1、懒汉式;2、饿汉式

懒汉式(线程不安全)

package Singleton;

 

public class LazySingleton {

    /**

     * 持有私有静态变量(也称类变量),防止被引用

     * 

     * 此处赋值为null,目的是实现延迟加载 (因为有些类比较庞大,所以延迟加载有助于提升性能)

     */

    private static LazySingleton instance = null;

   

    /** 私有构造方法,防止被实例化 */ 

    private LazySingleton(){   

    }

   

    /** 静态工厂方法,创建实例 --只不过这里是创建自己,而且只能创建一个 */ 

    public static LazySingleton getInstance() { 

        if (instance == null) { 

            instance = new LazySingleton(); 

        } 

        return instance

    }

   

    public void info(){

    System.out.println("info...");

    }

   

}

 

懒汉式(线程安全)

package Singleton;

 

public class LazySingletonSafe {

    private static LazySingletonSafe instance = null;

    private LazySingletonSafe(){

       

    }

//  在创建类的时候进行同步,所以只要将创建和getInstance()分开,单独为创建加synchronized关键字

    private static synchronized void syncInit(){

        if(instance == null){

            instance = new LazySingletonSafe();

        }

    }

    public static LazySingletonSafe getInstance(){

        if(instance == null) {

            syncInit();

        }

        return instance;

    }

   

   

}

 

饿汉式

package Singleton;

 

public class hungrySingleton {

    private static hungrySingleton instance = new hungrySingleton();

    private hungrySingleton(){

    }

    public static hungrySingleton getInstance(){

        return instance;

    }

    public void info() {

        System.out.println("...");

    }

}

 

 

测试类:

package Singleton;

 

public class client {

 

    /**

     * @param args

     */

    public static void main(String[] args) {

        // TODO Auto-generated method stub

        LazySingleton ls1 = LazySingleton.getInstance();

        ls1.info();

       

        LazySingleton ls2 = LazySingleton.getInstance();

        ls2.info();

       

        System.out.println(ls1 == ls2); 

         

        LazySingletonSafe lss1 = LazySingletonSafe.getInstance();

       

        LazySingletonSafe lss2 = LazySingletonSafe.getInstance();

       

        System.out.println(lss1 == lss2);

       

        hungrySingleton hs1 = hungrySingleton.getInstance();

        hungrySingleton hs2 = hungrySingleton.getInstance();

        System.out.println(hs1 == hs2);

    }

 

}

 

总结

用一个系统创建的那些对象的类对系统进行参数化有两种常用方法。

一种是生成创建对象类的子类;这对应于使用Factory Method模式。这种方法的主要缺点是,仅为了改变产品类,就可能需要创建一个新的子类。这样的改变可能是级联的。

另一种对系统进行参数化的方法更多的依赖于对象复合:定义一个对象负责明确产品对象类,并将它作为该系统的参数。这是Absolute Factory、Builder、和Prototype模式的关键特征。Abstract Factory由这个工厂对象产生多个类的对象。Builder由这个工厂对象使用一个相对复杂的协议,逐步创建一个复杂的产品。Prototype由该工厂对象通过拷贝原型对象来创建产品对象。在这种情况下,因为原型负责返回产品对象,所以工厂对象和原型是同一个对象。

通常设计以使用Factory Method开始,并且当设计者发现需要更大的灵活性时,设计便会向其他创建型模式演化。

Reference

http://blog.csdn.net/lhy_ycu/article/details/40031567

http://blog.csdn.net/zhangerqing/article/details/8194653

设计模式:可复用面向对象软件的基础

转载于:https://www.cnblogs.com/SailorXun/p/4266020.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值