设计模式之创建型模式(5种)

工厂方法模式和抽象工厂模式

简单工厂模式

通常方法都是静态的,所以也被称作静态工厂

虽然从理论上,简单工厂什么都能创造,但是对于简单工厂可创建对象的范围来说,通常不要太大,建议将其控制在一个独立组件级别或者一个模块级别,也就是一个组件或模块对应一个简单工厂

类名建议为“模块名称+Factory”,如“UserFacory”;方法名通常为“get+接口名称”或者“create+接口名称”,如“getUserBean”

public interfacePlayer{  //运动员接口
      public viod run();
      public void jump();
}
 
public classFootballPlayer implements Player{  //足球运动员
      public viod run(){
             //do something
      };
      public viod jump(){
             //do something
      };
}
 
public classBasketballPlayer implements Player{  //篮球运动员
      public viod run(){
             //do something
      };
      public viod jump(){
             //do something
      };
}
 
public class PlayerFactory{  //球员工厂类
      public static Player get FootballPlayer (){
             return new FootballPlayer();
      }
 
      public static Player get BasketballPlayer(){
             return new BasketballPlayer ();
      }
 
}
 
public class Test{  //足球俱乐部(篮球俱乐部与此类似)
      private Player goalkeeper;  //守门员
      private Player forward;  //前锋
      private Player defender;  //后卫
 
      public void clubTest(){
             this. goalkeeper = PlayerFactory. FootballPlayer();
             this. forward = PlayerFactory. FootballPlayer();
             this. defender = PlayerFactory. FootballPlayer();
      }
}    

简单工厂解决了不用接口、不用工厂而把具体类暴露给客户端时的混乱情形,接口就是用来封装和隔离具体实现的,目标就是不要让客户端知道封装内部的具体实现

简单工厂的本质目的就是:选择一个合适的实现类来使用

工厂方法模式

工厂方法模式和简单工厂模式的区别在于:简单工厂模式只有一个工厂类,而工厂方法模式有一组实现了相同接口的工厂类

public interfacePlayer{  //运动员接口
      public viod run();
      public void jump();
}
 
public classFootballPlayer implements Player{  //足球运动员
      public viod run(){
             //do something
      };
      public viod jump(){
             //do something
      };
}
 
public classBasketballPlayer implements Player{  //篮球运动员
      public viod run(){
             //do something
      };
      public viod jump(){
             //do something
      };
}
 
public interfaceClub{   //俱乐部的接口类
      public Player register();
}
 
public classFootballClub implements Club{  //足球俱乐部的具体工厂类
      public Player register(){
             return new FootballPlayer();
      };
}
 
public classBasketballClub implements Club{  //篮球俱乐部的具体工厂类
      public Player register(){
             return new BasketballPlayer ();
      };
}
 
public classTest{  //足球俱乐部(篮球俱乐部与此类似)
      private Player goalkeeper;  //守门员
      private Player forward;  //前锋
      private Player defender;  //后卫
 
      Club club = new FootballClub();
 
      public void clubTest (){
             this. goalkeeper = club.register();
             this. forward = club .register();
             this. defender = club .register();
      }
}    

抽象工厂模式

抽象工厂模式和工厂方法模式最大的区别在于需要创建对象的复杂程度上,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构

抽象工厂的目的是给客户端提供一个接口,可以创建多个产品族中的产品对象,使用抽象工厂还要满足以下条件:

1、系统中有多个产品族,而系统一次只能消费其中一族产品;

2、同属于同一个产品族的产品一起使用

在下例中,足球队的足球运动员和足球教练就是一个产品族,同理,篮球队一样。足球教练不能训练篮球队,篮球教练也不能训练足球队,他们是和运动员的类别捆绑在一起的

public interfacePlayer{  //运动员接口
      public viod run();
      public void jump();
}
 
public classFootballPlayer implements Player{  //足球运动员
      public viod run(){
             //do something
      };
      public viod jump(){
             //do something
      };
}
 
public classBasketballPlayer implements Player{  //篮球运动员
      public viod run(){
             //do something
      };
      public viod jump(){
             //do something
      };
}
 
pubic interfaceCoach{  //教练接口
      public void train(); 
}
 
public classFootballCoach implements Coach{  //足球教练
      public void train(){
             //足球教练带领足球运动员训练
      };
}
 
public classFootballCoach implements Coach{  //篮球教练
      public void train(){
             //篮球教练带领篮球运动员训练
      };
}
 
public interfaceAbstractClubFactory{  //俱乐部的抽象工厂
      public Coach createCoach();  //聘请教练
      public Player createPlayer();  //招纳运动员
}
 
public classFootballFactory implements AbstractClubFactory{ //足球队工厂
 
      public Coach createCoach(){  //聘请足球教练
             return new FootballCoach();   
      };
 
      public Player createPlayer(){  //招纳足球运行员
             return new FootballPlayer ();
      };
}
 
public class FootballFactoryimplements AbstractClubFactory{  //篮球队工厂
      public Coach createCoach(){  //聘请篮球教练
             return new FootballCoach();   
      };
 
      public Player createPlayer(){  //招纳篮球运行员
             return new FootballPlayer ();
      };
}
 
public classTest{  //测试类
      private Coach coach;
      private Player player;
      public void createClub(AbstractClubFactoryfactory){
             coach = factory. createCoach();
             player = factory. createPlayer();
      }
}    

测试类中,createClub(AbstractClubFactoryfactory)方法接受一个实现了AbstractClubFactory接口的类作为参数,然后就可以创建对应的球队了,如传进去的是FootballFactory,则会创建出足球教练和足球运动员,如果为FootballFactory,则会创建篮球运动员和篮球教练

假如现在要增加一个产品族——排球队,同样需要教练和运动员,需要从三处来考虑,首先需要增加一个实现了了Player接口的排球运行员类,然后需要增加一个实现了Coach接口的排球教练类,最后还需要一个实现了AbstractClubFactory、可以创建出排球教练和排球运动员的工厂类。可见,抽象工厂可以很好地支持开闭原则,即当需求放生改变时,是通过增加代码实现的,而不是对原有代码进行改动

单例模式

单例模式具有以下特点:

1、该类只有一个实例

2、该类自行创建实例,在该类内部创建自身的实例对象

3、向整个系统公开这个实例接口

对于单例模式,不管采用何种实现方式,它都是只关心类实例的创建问题,并不关心具体的业务逻辑

在Java里面实现的单例范围(即在什么范围内保证只有一个实例),是一个ClassLoader及其子ClassLoader的范围,如果一个虚拟机里面有多个ClassLoader,而这些ClassLoader都装载这个类的话,就算这个类是单例模式,它也会产生多个实例

一般建议单例模式的方法命名为getInstance

单例模式分为三种:懒汉式单例、饿汉式单例和登记式单例

懒汉式单例

也成为延迟加载,在类加载的时候并不创建实例,只有在第一次请求实例的时候才去创建,并且只创建一次

public classSingleton{
      private static Singleton uniqueInstance =null;
      private Singleton(){  //私有化构造方法,外部不能直接创建
      }
      //加上synchronized关键字,是为了防止在多线程环境下,多个线程同时调用getInstance会出错
      public static synchronized SingletongetInstance() { 
        if (instance == null) { 
            instance = new Singleton(); 
        } 
        return instance; 
    }
}

饿汉式单例

在类加载的时候,唯一实例已经被创建

public classSingleton{
      private static Singleton uniqueInstance =new Singleton();  //可以加上final关键字,防止外部修改
      private Singleton(){  //私有化构造方法,外部不能直接创建
      }
     
      public static Singleton getInstance() {
        return instance; 
    } 
}

登记式单例

public classSingleton{
      //登记簿,用来存放所有登记的实例
      private static Map<String,Singleton>registry = new HashMap();
      static{ //类加载的时候添加一个实例到登记簿
             Singleton sing = new Singleton();
             registry.put(sing.getClass().getName(),sing);
      }
 
      protected Singleton(){  //受保护的构造方法
      }
     
      //对于已登记的直接取出;还没登记的,先登记,再取出
      public static Singleton getInstance(Stringname) {
        if(name == null){
                           name = “Singleton”;
                    }
 
                    if(registry.get(name) ==null){
                    try{
                           registry.put(name,(Singleton)Class.froName(name).newInstance);
                    }catch(Exception e){
                           e.printstackTrace();
                    }
returnregistry.get(name);
    } 
     
}

例如,系统在很多地方都需要使用配置文件的内容,就可以考虑使用单例模式来节省内存资源

public classAppConfig {
      private static AppConfig instance = newAppConfig();
      private AppConfig(){
             //私有化构造方法
             readConfig();
      }
      public static AppConfig getInstance(){
             return instance;
      }
     
      private String parameteA;
      private String parameteB;
     
      public String getParameterA(){
             return parameteA;
      }
     
      public String getParameterB(){
             return parameteB;
      }
 
      private void readConfig(){
      Properties p = new Properties();
      InputStream in = null;
      try{
             in =AppConfig.class.getResourceAsStream(“AppConfig.properties”);
             p.load(in);
             this. ParameterA = p.getProperty(“paramA”);
             this. ParameterB = p.getProperty(“paramB”);
      }catch(IOException e){
             e.printStackTrace();
      }finally{
             try{
                    in.close();
             }catch(IOException e){
                    e.printStackTrace();
             }
      }
     
}
     
}
 
测试客户端
AppConfig config= AppConfig.getInstance();
String paramA =config.getParameterA();
String paramB =config.getParameterB();

下面是一种比较完美的代码构造,既可以使单例模式线程安全,也可以实现延迟加载

public classSingleton{
      //内部类,该内部类的实例与外部类的实例没有绑定关系,而且只有被调用时才会被装载,从而实现了延迟加载
      private static class SingletonHolder{
             private static Singleton instance =new Singleton();
      }
      private Singleton(){
             //私有化构造方法
      }
      public static Singleton getInstance(){
             return SingletonHolder.instance;
      }
     
}

当getInstance第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHoulder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,由于是静态的域,因此只会被虚拟机在装载类的时候初始化一次,并有虚拟机保证它的线程安全

建造者模式

在建造者模式里有个指导者角色,由指导者来管理建造者

建造者模式的目的是让设计和施工互相解耦

相同的方法,不同的执行顺序,产生不同的事件结果,可以考虑采用建造者模式

建造者模式是将复杂的内部创建封装在内部,对于外部调用的人,只需传入建造者和建造工具,至于内部是如何建造成成品的,调用者无需关心

如果将工厂模式看成一个汽车配件生产厂,生成不同类型的汽车配件,那么建造者模式就是一个汽车组装厂,通过对配件进行组装,返回一辆完整的汽车

工厂模式往往只关心你要的是什么,不关心这个东西的细节是什么,而建造者模式则关心的是这个东西的具体细节的创建

public classCar{  //汽车的实体类
      private String head;  //车头
      private String body;  //车身
      private String tail;  //车尾
      //省略了setter、getter方法
}
 
public abstract CarBuilder{  //汽车组装的抽象类
      //组装车头
      public abstract void makeHead();
      //组装车身
      public abstract void makeBody();
      //组装车尾
      public abstract void makeTail();
      //返回组装好的汽车对象
      public abstract Car getCar();
}
 
public classJeepBuilder extends CarBuilder{  //吉普车组装类
      Car car = new Car();
 
      public void makeHead(){
             car.setHead(“Jeep Head”);
      };
      public void makeBody(){
             car.setHead(“Jeep Body”);
      };
      public void makeTail(){
             car.setHead(“Jeep Tail”);
      };
 
      public Car getCar(){
             return car;
      };
}
//汽车组装操作的封装类
public classCarDirector {  //此类完成设计,决定了执行哪些方法和执行顺序
      public void makeCar(CarBuilder builder){
             builder.makeHead();
             builder.makeBody();
             builder.makeTail();
      }
}
 
测试类
CarDirectordirector = new CarDirector();
CarBuilderbuilder = new JeeprBuilder();
director.makeCar(builder);  //将吉普车的建造者传入指挥者中
Car car =builder.getCar();  //最后由建造者返回成品

设想,如果现在要增加一个生产公共汽车的流程,应该怎样改动代码?

首先,新建一个继承了CarBuilder类的BusBuilder,测试类中,将JeeprBuilder改为BusBuilder即可,其他部分一点不用改动

原型模式

原型模式是指使用原型实例来指定创建对象的类型,并且通过拷贝这些原型创建新的对象

通过拷贝方法所创建的对象是全新的对象,它们在内存中有全新的地址

在Java语言中实现原型模式:

public classPrototype implements Cloneable { 
 
    public Object clone() throws CloneNotSupportedException { 
                    //super.clone()调用的是Object的clone()方法
        Prototype proto = (Prototype) super.clone(); 
        return proto; 
    } 
} 
 
测试类
Prototype proto1= new Prototype();
Prototype proto2= proto1.clone();

在拷贝的时候有一个浅复制与深复制的概念

浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。基本类型包括int、long、String等原始类型,同时满足以下两个条件的都不会被拷贝:1、类的成员变量,而不是方法内的变量;2、必须是一个对象,而不是一个基本类型

深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。

public classThing implements Cloneable{
      private ArrayList<String> arrayList= new ArrayList<String>();
      public thing clone{
             Thing thing = null;
             try{
                    thing =(Thing)supper.clone();
             }catch(CloneNotSupportedExceptione){   
                    //异常处理
             }
 
             return thing;
      }
 
      public void setValue(String value){
             this.arrayList.add(value);
      }
 
      public ArrayList<String> getValue(){
             return arrayList;
      }
     
}
 
测试类
Thing thing =new Thing();
thing.setValue(“张三”);
 
Thing cloneThing= thing.clone();
cloneThing.setValue(“李四”);
System.out.println(thing.getValue());

预想的运行结果是“张三”,实际上打印出来的是“张三,李四”

这时因为以上进行的是浅复制,thing中的arrayList并没有复制一个新的对象出来,thing和cloneThing实际上共用同一个arrayList,你改,我改,大家都能改,是一种非常不安全的方式

public classPrototype implements Cloneable, Serializable { 
 
    private static final long serialVersionUID= 1L; 
    private String string; 
 
    private SerializableObject obj; 
 
    /* 浅复制 */ 
    public Object clone() throwsCloneNotSupportedException { 
        Prototype proto = (Prototype)super.clone(); 
        return proto; 
    } 
 
    /* 深复制 */ 
    public Object deepClone() throwsIOException, ClassNotFoundException { 
 
        /* 写入当前对象的二进制流 */ 
        ByteArrayOutputStream bos = newByteArrayOutputStream(); 
        ObjectOutputStream oos = newObjectOutputStream(bos); 
        oos.writeObject(this); 
 
        /* 读出二进制流产生的新对象 */ 
        ByteArrayInputStream bis =
newByteArrayInputStream(bos.toByteArray()); 
        ObjectInputStream ois = newObjectInputStream(bis); 
        return ois.readObject(); 
    } 
 
    public String getString() { 
        return string; 
    } 
 
    public void setString(String string) { 
        this.string = string; 
    } 
 
    public SerializableObject getObj() { 
        return obj; 
    } 
 
    public void setObj(SerializableObject obj){ 
        this.obj = obj; 
    } 
 
} 
 
classSerializableObject implements Serializable { 
    private static final long serialVersionUID= 1L; 
} 

如果需要实现深复制,可以通过序列化(Serialization)等方式来实现,序列化就是将对象写入到流的过程,写到流中的对象是原有对象的一个拷贝,而原对象仍然存在于内存中

能够序列化的对象其类必须实现Serializable接口

时间: 2024-10-12 11:57:12

设计模式之创建型模式(5种)的相关文章

设计模式之创建型模式(上)

没有总结的学习不算学习,这一个月的学习可谓收获多多啊,接下来与大家分享一下. 一.设计模式的分类 总体来说设计模式分为三大类: 1.创建型模式,共五种. 2.结构型模式,共七种. 3.行为型模式,共十一种. 首先研究创建型模式 二. 概述 创建型模式,就是用来创建对象的模式,抽象了实例化的过程.它帮助一个系统独 立于如何创建.组合和表示它的那些对象. 三. 为什么需要创建型模式 所有的创建型模式都有两个永恒的主旋律: 第一,它们都将系统使用哪些具体类的信息封装起来: 第二,它们隐藏了这些类的实例

设计模式 (创建型模式)

  设计模式 创建型模式 1.创建型模式         创建型模式,包括了5种设计模式,分别是 Singleton (单例模式),Factory(工厂模式),AbstractFactory(抽象工厂模式),Builder(创建者),Prototype(原型) ,创建型模式主要作用就是抽象了实例化过程.他们帮助一个系统独立于如何创建.组合和表示他的那些对象.一个类创建型模式使用继承改变被实例化的类.而一个对象创建型模式将实例化委托给另一个对象. 2.Singleton (单例模式)      单

设计模式系列 - 创建型模式

单例模式 懒汉式,线程不安全. 除非是单线程程序,否则不推荐使用. public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } } 饿汉式,线程安全 当程序总是使用这个

设计模式之创建型模式

一.前言 设计模式应该是在软件工程的背景下进行讨论的,而不是为了设计模式而论设计模式.设计模式是软件工程面向对象设计工作中一个抽象.归纳.总结的过程.软件设计的最高目标和最高准则就是易扩展,易复用,易维护, 灵活性高,高可用,稳定性高一切的设计原则和设计模式最终的目标都是向这个目标靠拢的. 二.面向对象设计六大原则 任何的设计模式都是基于面向对象的特性(抽象.封装.继承.多态)和设计原则进行设计和实现的,是面向对象设计原则的在不同场景下的实现方案. 抽象:抽离变化的部分,引入抽象层,实现具体实现

设计模式1—创建型模式

模式 在一定环境中解决某一问题的方案,包括三个基本元素--问题,解决方案和环境. 大白话:在一定环境下,用固定套路解决问题. 设计模式(Design pattern) 是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于己于他人于系统都是多赢的:设计模式使代码编制真正工程化:设计模式是软件工程的基石脉络,如同大厦的结构一样. 设计模式的分类(Gang of Four的"DesignPatt

Java设计模式之创建型模式

创建型模式分为五类:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式 一.工厂方法模式:接口-实现类-工厂类 工厂类的目的是为了产生Sender对象,通过不同的参数传入产生不同的对象. 将工厂类中的工厂方法改为多个工厂方法即为多个工厂方法的设计模式 将工厂类中的工场方法改为static即为静态工厂方法设计模式 二.抽象工厂方法模式:接口-实现类-工厂类 特点是: 工厂类实现某个接口,利于以后扩展,比如可以增加BlueTooth的工厂类. 工厂设计模式是抽象工厂设计模式的一个特例. 三.

设计模式_创建型模式——工厂方法

工厂方法(Factory Method):工厂方法模式属于类的创建型模式.在工厂方法模式中,父类负责定义创建产品对象的工厂接口,而子类则负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成,即由子类来决定究竟应该实例化哪一个类. abstract Product factoryMethod(String type) abstract:工厂方法是抽象的,依赖子类来处理对象的创建 Product:工厂方法返回一个产品,超类中定义的方法,通常使用到工厂方法的返回值 String:工厂方法

设计模式_创建型模式_简单工厂模式

转载自:http://blog.csdn.net/lovelion  作者:刘伟 简单工厂模式并不属于GoF 23个经典设计模式,但通常将它作为学习其他工厂模式的基础,它的设计思想很简单,其基本流程如下:        首先将需要创建的各种不同对象(例如各种不同的Chart对象)的相关代码封装到不同的类中,这些类称为具体产品类, 而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类: 然后提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方

设计模式之“创建型模式”

创建型模式主要分为五大模式,分别为:抽象工厂模式.建造者模式.工厂方法模式.原型模式.单例模式. 抽象工厂模式 提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 一.优点 1.易于交换产品系列. 2.它让具体的创建实例过程与客户端分离. 二.反射 Assembly.Load("程序集名称").CreateInstance("命名空间.类名称")需要在程序顶端写上using System.Reflection;来引用Reflection所有用简单工

设计模式_创建型模式

创建型模式与对象创建有关. 1. Abstract Factory (抽象工厂) 定义:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 适用:一个系统要独立于它的产品的创建.组合和表示时. 与工厂模式的区别:工厂模式的一个工厂接口的子类只能实例化一个产品:抽象工厂能实例多个产品. 例子代码: package designModel; // 产品1 interface IProduct1 { } class Product1A implements IProduct1 { }