Java设计模式学习笔记之构造型模式

一、构造型模式概念介绍:

 1、构造函数: 

   若要创建一个Java类,通常会提供多个构造函数。构造函数是有用的,尽管只有客户类知道该使用哪个构造函数以

及传递什么参数来创建类。

  初始化对象的常见方法是调用new操作符,也可以使用反射。反射提供了能将类型与类型成员像对象一样操作的能

力。

 一般情况下,你需要为自己开发的类提供构造函数使其能够被初始化。这些构造函数可能相互调用协作,并且类中

的每个构造函数最终都会去调用超类的构造函数。调用构造函数的常规做法是使用new操作符,但也可以使用反射来初始化和使用

对象。

 2.构造型模式的意图:

 在设计一个新类时,Java构造函数的这些特性可以提供许多选择。然而,只有在类的用户知道该如何初始化类,以及传递

所需参数时,构造函数才是有效的。

  构建者模式:在请求创建对象前,逐步收集创建对象需要的信息;

  工厂方法模式:决定推迟实例化对象;

  抽象工厂模式:创建一族具有某些共同特征的对象;

  原型模式:根据现有对象创建一个新的对象;

  备忘录模式:通过包含内部状态的静态版本重新构建一个对象。

 每种设计模式的意图都是为了解决某种场景下的问题。构造型模式的设计就是为了让客户类不通过类构造函数来创建

对象。

二、构建者(Builder)模式:

  当创建一个对象时,并不一定拥有创建该对象的全部信息,如需要逐步获取创建对象的信息,更方便的做法就是分步骤构建

对象。这种情况通常发生在构建解释器和用户界面上。或者,当类的构造函数过于复杂,却对类的重点功能没有太大影响时,就

可能需要让类变得更小一些。

  构建者模式的意图是将类的构建逻辑转移到类的实例化外部。

1.构建者的角色及实例示例:

 Builder:为创建一个产品对象的各个部件指定抽象接口:

public interface PersonBuilder {  
     void buildHead();  
     void buildBody();  
     void buildFoot();  
     Person buildPerson();  
}

 ConcreateBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索

产品的接口。

public class ManBuilder implements PersonBuilder {  
     Person person;  
     public ManBuilder() {  
          person = new Man();  
     }  
     public void buildbody() {  
          person.setBody("建造男人的身体");  
     }  
     public void buildFoot() {  
          person.setFoot("建造男人的脚");  
     }  
     public void buildHead() {  
          person.setHead("建造男人的头");  
     }  
     public Person buildPerson() {  
          return person;  
     }  
}  

 Director:构造一个使用Bulider接口的对象,指导构建过程;

public class PersonDirector {  
     public Person constructPerson(PersonBuilder pb) {  
          pb.buildHead();  
          pb.buildBody();  
          pb.buildFoot();  
          return pb.buildPerson();  
     }  
}  

 Product:表示被构造的复杂对象。ConcreateBuilder创建产品的内部表示并定义它的装配过程,包含定义组成部件的类,

包括将这些部件装配成最终产品的接口。

public class Person {  
     private String head;  
     private String body;  
     private String foot;  
  
     public String getHead() {  
          return head;  
     }  
     public void setHead(String head) {  
          this.head = head;  
     }  
     public String getBody() {  
          return body;  
     }  
     public void setBody(String body) {  
          this.body = body;  
     }  
     public String getFoot() {  
          return foot;  
     }  
     public void setFoot(String foot) {  
          this.foot = foot;  
     }  
}  
public class Man extends Person {  
     public Man(){  
          System.out.println(“开始建造男人");  
     }  
}  
public class Woman extends Person {  
     public Woman(){  
          System.out.println(“开始建造女人");  
     }  
} 

 2.建造者模式的变种:

 建造者模式在使用过程可以演化出多种形式:

如果具体的被创建对象只有一个的话,可以省略抽象的Builder和Director,让ConcreateBuilder自己扮演指导者和建造者

双重角色,甚至ConcreateBuilder也可以放到Product里面实现。

 在《Effective Java》中提到“遇到多个构造器参数时要考虑用构建器”,其实这里的构建器就属于建造者模式,只是里面

把四个角色都放在具体的产品里了。

public class Man {  
     private String head;  
     private String body;  
     private String foot;  
  
     public String getHead() {  
          return head;  
     }  
     public void setHead(String head) {  
          this.head = head;  
     }  
     public String getBody() {  
          return body;  
     }  
     public void setBody(String body) {  
          this.body = body;  
     }  
     public String getFoot() {  
          return foot;  
     }  
     public void setFoot(String foot) {  
          this.foot = foot;  
     }  
} 

public class ManBuilder{  
     Man man;  
     public ManBuilder() {  
          man = new Man();  
     }  
     public void buildbody() {  
          man.setBody("建造男人的身体");  
     }  
     public void buildFoot() {  
          man.setFoot("建造男人的脚");  
     }  
     public void buildHead() {  
          man.setHead("建造男人的头");  
     }  
     public Man builderMan() {  
          buildHead();  
          buildBody();  
          buildFoot();  
          return man;  
     }  
} 

 3.小结:

 构建者模式将复杂对象的构建逻辑从对象本身抽离出来,这样能够简化复杂的对象。构建者关注目标类的构建过程,目标类

关注合法实例的业务本身。这种做的好处是在实例化目标类前,确保得到的是一个有效的对象,并且不会让构建逻辑出现在目标

本身。构建者构建类对象的过程通常是分步骤的,这使得该模式通常 被应用于解析文本以创建对象的场景

二、工厂方法(Factory Method)模式:

 创建类时,通常可以同时定义多个构造函数,然后让它们创建类的实例。然而有时候,客户代码虽然需要某个对象,却不关

心或者不需要关心这个对象究竟是由哪个类创建而来的。

 工厂方法模式的意图是定义一个用于创建对象的接口,并控制返回哪个类的实例。

 1.识别工厂方法:

 工厂方法模式不仅要求有一个创建新对象的方法,还要让客户代码无须了解具体实例化的类。工厂方法模式通常包含了

若干类类,这些类实现了相同的操作。返回了相同的抽象类型,然而这些操作的内部,实际上却实例化了不同的类,并且,这些类

都实现了上述抽象类型。当客户代码请求一个新对象时,这个新对象由哪个类实例化,取决于工厂对象接收创建请求时的行为。

 2.控制要实例化的类:

客户代码使用类的某个构造函数来实例化类。但是有时候,客户代码并不知道使用哪个类去创建它所需要的对象。如在迭

代器模式中,客户代码需要的迭代器的类取决于客户代码想要遍历的容器的类型。

 3. 并行层次结构中的工厂方法模式:

  在使用并行层次结构对问题域进行建模时,常常会使用工厂方法模式。一个并行层次结构是一对类层次结构。其中

一个类在一个层次,与其相关的类的另一层次。当将现有类层次结构的部分行为移除该层次后。并行层次结构就会显露出来。

 4.工厂方法模式的角色及实例示例:

 工厂方法模式核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用

和方便后期维护拓展的目的。它的核心结构有抽象产品类、具体产品类、抽象产品、具体产品:

  抽象产品角色:包含具体产品继承的父类或者实现的接口,一般是抽象类或接口

public abstract class Product {                                                                              
    /**
     * 产品类的公共方法
     */

    public void method1(){
        //业务逻辑处理
    }

    //抽象方法
    public abstract void method2();
}

具体产品类:具体工厂角色所创建的对象就是此角色的实例

public class ConcreteProduct1 extends Product{
    /**
     * 具体产品类
     */

    @Override                                                                                                
    public void method2() {
        // 业务逻辑处理

    }
}
public class ConcreteProduct2 extends Product{
    /**
     * 具体产品类
     */

    @Override
    public void method2() {
        //  业务逻辑处理

    }

}

 抽象工厂类:是模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或必须继承的父类。

public class ConcreteCreator extends Creator{
    /**
     * 具体工厂类
     */

    @SuppressWarnings("unchecked")
    @Override
    public <T extends Product> T createProduct(Class<T> c) {
        Product product = null;
        try {
            product = (Product) Class.forName(c.getName()).newInstance();
        } catch (Exception e) {
            // 异常处理
        }
        return (T)product;
    }
}

 场景类:

public class Client {

    /**
     * 场景类
     */
    @SuppressWarnings("unused")
    public static void main(String[] args) {
        Creator creator = new ConcreteCreator();
        Product product = creator.createProduct(ConcreteProduct1.class);
        /**
         * 继续业务处理
         */
    }

}

 5.小结;

 当你不想让客户代码决定实例化哪个类时,常常可以运用工厂方法模式。共产方法模式还可以用于当客户代码不知道它

需要创建哪个对象类的时候。另外,在并行类层次结构中使用该模式可以避免类的规模过于庞大。工厂方法模式可以根据一个类

层次中的子类,确定另一个相关层次中哪个一个类被实例化,从而建立对应的并行层次结构。

三、抽象工厂(Abstract Factory):

 在创建对象时,有时会指定具体类去实例化一个对象。可以使用工厂方法模式来定义一个外部方法以决定实例化哪个类。但

有时,控制实例化哪个类的因素可能与很多类息息相关。

 抽象工厂模式又名工具箱,其意图时允许创建一族相关或互相依赖的对象。

 1.抽象工厂模式代码:

 产品类:

//发动机以及型号    
public interface Engine {    
  
}    
public class EngineA extends Engine{    
    public EngineA(){    
        System.out.println("制造-->EngineA");    
    }    
}    
public class EngineBextends Engine{    
    public EngineB(){    
        System.out.println("制造-->EngineB");    
    }    
}    
  
//空调以及型号    
public interface Aircondition {    
  
}    
public class AirconditionA extends Aircondition{    
    public AirconditionA(){    
        System.out.println("制造-->AirconditionA");    
    }    
}    
public class AirconditionB extends Aircondition{    
    public AirconditionB(){    
        System.out.println("制造-->AirconditionB");    
    }    
}  
   创建工厂类:
//创建工厂的接口    
public interface AbstractFactory {    
    //制造发动机  
    public Engine createEngine();  
    //制造空调   
    public Aircondition createAircondition();   
}    
  
  
//为宝马320系列生产配件    
public class FactoryBMW320 implements AbstractFactory{    
        
    @Override    
    public Engine createEngine() {      
        return new EngineA();    
    }    
    @Override    
    public Aircondition createAircondition() {    
        return new AirconditionA();    
    }    
}    
//宝马523系列  
public class FactoryBMW523 implements AbstractFactory {    
    
     @Override    
    public Engine createEngine() {      
        return new EngineB();    
    }    
    @Override    
    public Aircondition createAircondition() {    
        return new AirconditionB();    
    }    
  
  
} 

 客户:

public class Customer {    
    public static void main(String[] args){    
        //生产宝马320系列配件  
        FactoryBMW320 factoryBMW320 = new FactoryBMW320();    
        factoryBMW320.createEngine();  
        factoryBMW320.createAircondition();  
            
        //生产宝马523系列配件    
        FactoryBMW523 factoryBMW523 = new FactoryBMW523();    
        factoryBMW320.createEngine();  
        factoryBMW320.createAircondition();  
    }    
}  


四、原型(Prototype)模式:

 设计一个类时,通常会提供构造函数,使得客户端应用程序能够通过它去创建对象。但在某些情况下,可能不允许类的调

用者直接调用构造函数。在构造型设计模式中,如构建者模式、工厂方法模式、抽象工厂模式都可以避免客户端直接电影构造

函数。这些模式都是通过引入新类,代表客户端代码实例化合适的类对象。原型模式创建对象的方式与这些模式殊途同归。

 原型模式的意图是通过复制一个现有的对象来生成新的对象,而不是通过实例化的方式。

 1.作为工厂的原型:

 创建对象的常规方法是调用类的构造函数。原型模式提供了灵活的解决方案,你可以在运行时决定使用哪个对象。然而

Java程序开发红的原型方法并不允许对象拥有与父对象不同的方法。因此可能需要重现考虑原型模式的利弊,甚至需要先试试原

型模式是否符合需求。为了使用原型模式,需要掌握Java语言的复杂对象机制。

 2.利用克隆进行原型化:

 原型模式的意图是通过复制一个样本来创建新对象。当复制一个对象时,新对象将拥有与原对象相同的属性和方法。

当然,这个新对象还可以继承部分甚至全部原对象的数据值。

 3.原型模式的角色扮演及实例示例:

 实现Cloneable接口。在Java中有一个Cloneable接口,他的作用只有一个,就是在运行时通知虚拟机可以安全地在实

现了此接口的类上使用clone方法。在Java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出

CloneNotSupportedException异常。

  重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象

的一个拷贝,但是其作用域protected类型,一般的类无法调用,因此,在原型类需要将clone方法的作用域修改为public类型。

 代码实现:

class Prototype implements Cloneable {    
    public Prototype clone(){    
        Prototype prototype = null;    
        try{    
            prototype = (Prototype)super.clone();    
        }catch(CloneNotSupportedException e){    
            e.printStackTrace();    
        }    
        return prototype;     
    }    
}    
    
class ConcretePrototype extends Prototype{    
    public void show(){    
        System.out.println("原型模式实现类");    
    }    
}    
    
public class Client {    
    public static void main(String[] args){    
        ConcretePrototype cp = new ConcretePrototype();    
        for(int i=0; i< 10; i++){    
            ConcretePrototype clonecp = (ConcretePrototype)cp.clone();    
            clonecp.show();    
        }    
    }    
}    

使用原型模式创建对象比直接new一个对象在性能上要好得多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。

五、备忘录(Memento)模式:

 有时候想创建的对象已经在系统中存在。如当用户执行撤销操作,是系统回滚到之前的某一状态,或重新执行之前搁置的

工作时,就会出现这种情形。

 备忘录模式的意图是为对象状态提供储存和恢复功能。

 1.备忘录模式的结构:

 发起者角色(Originator):负责创建一个备忘录用以记录当前时刻它的内部状态,可以使用备忘录恢复内部状态。

public class Emp {
    private String name;
    private int age;
    private int salary;


    //进行备份操作,并返回一个备忘录对象
    public EmpMemento memento(){
        return new EmpMemento(this);
    }

    //进行数据恢复,恢复成备忘录中对象的值
    public void recovery(EmpMemento em){
        this.name=em.getName();
        this.age=em.getAge();
        this.salary=em.getSalary();
    }


    public Emp(String name, int age, int salary) {
        this.name = name;
        this.age = age;
        this.salary = salary;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }

}

 备忘录角色(Memento):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。

public class EmpMemento {
    private String name;
    private int age;
    private int salary;

    public EmpMemento(Emp emp){
        this.name=emp.getName();
        this.age=emp.getAge();
        this.salary=emp.getSalary();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getSalary() {
        return salary;
    }
    public void setSalary(int salary) {
        this.salary = salary;
    }
}

 管理者觉得(CareTake):负责保存好备忘录。

/**
 * 管理者角色:负责管理备忘录类,示例只保存了一个备忘录对象,可以通过设置栈保存多个对象
 */
public class CareTaker {
    private EmpMemento memento;

    public EmpMemento getMemento() {
        return memento;
    }

    public void setMemento(EmpMemento memento) {
        this.memento = memento;
    }

}

 2.小结:

 借助备忘录模式,可以捕捉对象的状态,以便于将来把对象恢复为以前的状态。具体采用哪种方式来储存对象状态,取

决于对象状态需保存时间的长短。为了支持对象跨多个会话的持久性储存,可以使用对象序列化或其他方式来保存备忘录。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值