zoukankan      html  css  js  c++  java
  • Java设计模式概述之创建型模式

    Java一共有23种设计模式,23种设计模式大致分为三大类:创建模式、结构化模式、行为模式。

    Tip:由于23三种设计模式的篇幅较长,先来介绍我们比较熟悉的建造者模式。

    一、单例模式(Singleton)


    单例模式中的单例是指唯一的实例对象。Java API中的Calendar类就利用了单例模式。相信大家应该对这条语句不陌生:Calendar.getInstance()。这条语句创建了一个单例。再如在某些应用场景下,需要重复获取同一个实例对象,不断new对象势必会造成Java堆中的内存浪费,因此,我们可以把该对象单例化,达到重复利用统一资源的目的。

    单例模式代码:

    /**
     * @author Hanlin Wang
     */
    
    public class SingletonMode {
        public static void main(String[] args) {
            Singleton instance = Singleton.getInstance();
            Singleton instance2 = Singleton.getInstance();
            System.out.println(instance==instance2);
        }
    }
    
    //懒汉式
    class Singleton{
        //定义一个Singleton类型的变量。private防止外部访问;static能够以静态方式获取;null实现延迟加载。
        private static Singleton instance = null;
        //私有化构造方法,防止外部创建该对象。
        private Singleton(){}
        //synchronized方法:使单例对象创建时,线程安全。
        private static synchronized void syncInit(){
            if (null == instance) {
                instance = new Singleton();
            }
        }
        //公共的、静态的方法,获取唯一的实例。
        public static Singleton getInstance(){
            if (null == instance) {
                syncInit();
            }
            return instance;
        }
    }

    单例模式通过类创建唯一的实例对象。形如:Singleton.getInstance()。而我们经常通过Object obj = new Object();创建实例对象,一定要区分清楚:类创建实例对象是把new对象语句插入到该类的一个静态方法中,从而可以以类名.方法名调用创建实例对象的方法。由于要通过类创建单例,必须把创建对象的方法加上static修饰符。要能访问该方法,所以方法还要加上public修饰符。又由于静态方法只能作用于静态变量,所以单例对象的引用变量instance必须用static修饰,这样instance静态变量就被存入了方法区(详见JVM虚拟机内存划分概述)。防止外部直接访问instance静态变量,加上private修饰符。

    还有大片细节需要大家去细心琢磨,代码已上注释。

    二、工厂模式(Factory)


    工厂模式分为三大类:普通工厂模式、工厂方法模式、静态工厂方法模式。

    1、普通工厂模式

    普通工厂模式内部定义一个生产方法,方法中接受一个参数,根据参数值的不同来创建相应的对象。

    代码:

    //普通工厂模式
    class Factory{
        public C produce(String type){
            if ("A".equals(type)) {
                return new A();
            } else if ("B".equals(type)) {
                return new B();
            } else {
                return null;
            }
        }
    }
    
    //定义一个接口类C
    interface C{
        void run();
    }
    
    //定义两个实现类A、B
    class A implements C{
        public void run(){
            System.out.println("A's running");
        }
    }
    
    class B implements C{
        public void run(){
            System.out.println("B's running");
        }
    }
    
    public class FactoryMode {
        public static void main(String[] args) {
            /*普通工厂模式
            Factory factory = new Factory();
            C a = factory.produce("A");
            C b = factory.produce("B");
            a.run();
            b.run();*/
        }
    }

    可见,根据传入参数名的不同来决定生产何类对象。

    2、工厂方法模式

    普通工厂模式通过传入的参数来判断创建何种对象,这样存在一个问题,如下:
    public C produce(String type)
    返回的是C类型,虽然这样很好的利用了多态的特性,但我们无法得知返回的对象是C接口的哪一个实现类,A?还是B?。

    因此,工厂方法模式通过在工厂类中定义一系列方法来实现精准创建具体类型的实力对象。

    代码:

    //工厂方法模式
    class MethodFactory{
        public A produceA(){
            return new A();
        }
        public B produceB(){
            return new B();
        }
    }
    
    //定义一个接口类C
    interface C{
        void run();
    }
    
    //定义两个实现类A、B
    class A implements C{
        public void run(){
            System.out.println("A's running");
        }
    }
    
    class B implements C{
        public void run(){
            System.out.println("B's running");
        }
    }
    
    public class FactoryMode {
        public static void main(String[] args) {
            MethodFactory factory = new MethodFactory();
            A a = factory.produceA();
            B b = factory.produceB();
            a.run();
            b.run();
        }
    }

    3、静态工厂方法模式

    静态工厂方法模式与工厂方法模式类似,以静态的方式调用工厂类的方法。我们只需在工厂方法模式的基础上给工厂类中的方法加上static修饰符。

    代码:

    //静态工厂方法模式
    class StaticFactory{
        public static A produceA(){
            return new A();
        }
        public static B produceB(){
            return new B();
        }
    }

    三、抽象工厂模式(Abstract Factory)


    普通(class)工厂模式 VS 抽象(interface、abstract class)工厂模式。这么一形(dou)象(bi)的比较,相信大家肯定猜到区别了。抽象工厂模式把工厂类中的方法抽取出来放在了一个interface中,工厂类实现interface中的方法就是抽象工厂模式。由于是工厂类继承工厂类接口,因此不能使用static关键字来修饰工厂类的方法。

    代码:

    class Factory{
        public C produce(String type){
            if ("A".equals(type)) {
                return new A();
            } else if ("B".equals(type)) {
                return new B();
            } else {
                return null;
            }
        }
    }
    
    //定义一个接口类C
    interface C{
        void run();
    }
    
    //定义两个实现类A、B
    class A implements C{
        public void run(){
            System.out.println("A's running");
        }
    }
    
    class B implements C{
        public void run(){
            System.out.println("B's running");
        }
    }
    
    //抽象工厂模式。创建一个Provider,被各种工厂类实现。
    interface Provider{
        C produce();
    }
    
    class FactoryA implements Provider{
        public C produce(){
            return new A();
        }
    }
    
    class FactoryB implements Provider{
        public C produce(){
            return new B();
        }
    }
    
    public class FactoryMode {
        public static void main(String[] args) {
            FactoryA factoryA = new FactoryA();
            FactoryB factoryB = new FactoryB();
            C a = factoryA.produce();
            C b = factoryB.produce();
            a.run();
            b.run();
        }
    }

    四、建造者模式(Builder)


    工厂模式专注于创建单一对象,建造者模式在工厂模式的基础上侧重对象的批量创建。

    代码:

    /**
     * @author Hanlin Wang
     */
    
    //工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象,多个部分。因此,是选择工厂模式还是建造者模式,依实际情况而定。
    public class BuilderMode {
        public static void main(String[] args) {
            Builder builder = new Builder();
            builder.batchProduceA(10);
            builder.batchProduceB(15);
        }
    }
    
    class Builder{
        private ArrayList<C> list = new ArrayList<C>();
        public void batchProduceA(int count){
            for (int i = 0; i < count; i++) {
                list.add(new A());
            }
        }
        public void batchProduceB(int count){
            for (int i = 0; i < count; i++) {
                list.add(new B());
            }
        }
    }

    建造者模式通过for循环批量创建了A、B对象,并将A、B对象存储到List集合对象中。

    五、原型模式(Prototype)


    原型模式用于克隆对象。原型模式克隆分浅克隆和深克隆。利用原型模式克隆,可以适当代替new对象这一操作,拥有new对象所不具备的,赋值属性,对象状态等等。

    浅克隆只克隆对象本身,不克隆对象属性,而克隆对象属性的引用。

    深克隆不但克隆对象本身,还克隆了对象的属性,是完全唯一的。若实现序列化接口,还可进行序列化和反序列化操作。

    代码:

    import java.io.IOException;
    import java.util.ArrayList;
    
    /**
     * @author Hanlin Wang
     */
    
    public class PrototypeMode {
        public static void main(String[] args) throws CloneNotSupportedException, ClassNotFoundException, IOException {
            Prototype proto = new Prototype();
            Prototype clone1 = (Prototype) proto.clone();
            Prototype clone2 = (Prototype) proto.clone();
            System.out.println(clone1 == clone2);
            System.out.println(clone1.getInfo() == clone2.getInfo());
    
            Prototype deepClone1 = (Prototype) proto.deepClone();
            Prototype deepClone2 = (Prototype) proto.deepClone();
            System.out.println(deepClone1 == deepClone2);
            System.out.println(deepClone1.getInfo() == deepClone2.getInfo());
    
            /*false
            true
            false
            false*/
        }
    }
    
    class Prototype implements Cloneable{
        private ArrayList<String> info = new ArrayList<String>();
        public ArrayList<String> getInfo() {
            return info;
        }
        public void setInfo(ArrayList<String> info) {
            this.info = info;
        }
        //浅克隆
        public Object clone() throws CloneNotSupportedException{
            Prototype proto = (Prototype) super.clone();
            return proto;
        }
        //深克隆
        public Object deepClone() throws CloneNotSupportedException{
            Prototype proto = (Prototype) super.clone();
            proto.info = (ArrayList<String>) info.clone();
            return proto;
        }
    }

    以上就是Java设计模式中创建型模式的概述,相信大家应该有所收获。

    读者朋友也可以给我留言,我会认真回复,什么类型的意见建议都可以,欢迎讨论。

    随后我会推出后续的有关设计模式的博文,我们不见不散~

  • 相关阅读:
    ASP.NET连接SQL、Access、Excel数据库(二)——连接实例
    浅论cherry机械键盘与其在war3中的表现
    山寨一个PetShop(Task100)——注册界面(配置aspnetdb数据库)
    ASP.NET连接SQL、Access、Excel数据库(三)——工厂模式
    山寨一个PetShop(Task100)——注册界面(配置CreateUserWizard)
    Visual Studio2008的微软官方下载地址
    cocos2d对动画的各种操作
    自定义控件(Task01)——可以设置属性的控件
    Objectivec 枚举类型
    DLL技术应用01 零基础入门学习Delphi44
  • 原文地址:https://www.cnblogs.com/wanxi/p/6476243.html
Copyright © 2011-2022 走看看