建造者模式
建造者模式(Builder Pattern)
- 概述:主要目的是将一个复杂对象的构建过程与其表示相分离,从而可以创建具有不同表示形式的对象。(使得同样的构造过程可以创建不同的表示)
结构:
建造者模式包含以下几个主要角色:
抽象建造者(Builder):规定了实现复杂对象的哪些部分的创建,并不设计具体的部件对象的创建。
具体建造者(Concrete Builder):实现抽象建造者接口,完成复杂产品的各个部件的具体创建方法。在构建过程完成之后,提供产品的实例。
产品(Product):要构建的复杂对象。产品类通常包含多个部分或属性。
指导者(Director):负责调用具体建造者的方法来构建产品,指导者并不了解具体的构建过程,只关心产品的构建顺序和方式
-Bike产品.java
public class Bike{ private String frame; private String seat;
public String getFrame(){ return frame; } public void setFrame(String frame){ this.frame=frame; } public String getSeat(){ return seat; } public void setSeat(String seat){ this.seat=seat; } }
|
Builder抽象建造者.java
public abstract class Builder{
protected Bike bike=new Bike(); public abstract void buildFrame(); public abstract void buildSeat();
public abstract Bike createBike();
}
|
具体建造者1.java
public class MobikeBuider extends Builder { @Override public void builerFrame() { bike.setFrame("摩拜碳钎维车架"); }
@Override public void builerSeat() { bike.setSeat("摩拜真皮车座");
}
@Override public Bike createBike() { return bike; } }
|
具体建造者2.java
public class OfoBuilder extends Builder{ @Override public void builerFrame() { bike.setFrame("Ofo铝合金车架"); }
@Override public void builerSeat() { bike.setSeat("Ofo橡皮车座");
}
@Override public Bike createBike() { return bike; } }
|
指导者(Director).java
private Builder builder;
public Direactor(Builder builder){ this.builder=builder; } public Bike construct(){ builder.buildFrame(); builder.buildSeat(); return builder.createBike();
}
|
总结:
- 指挥者用于指导具体构建者如何构建产品,控制调用的先后顺序,并向调用者返回完整的产品类,但是有些情况下需要简化系统结构,就可以把指挥者类和抽象建造者进行合并。
public abstract class Builder {
protected Bike bike = new Bike();
public abstract void builerFrame();
public abstract void builerSeat();
public abstract Bike createBike();
public Bike build(){ this.builerFrame(); this.builerSeat(); return this.createBike(); } }
|
- 这样做确实简化了系统结构,但是同时家中了抽象建造者类的职责,也不太符合单一职责原则,如果construct过于复杂,建议还是封装到Director中。
使用场景:
- 需要生成的对象具有复杂的内部结构。
- 需要生成的对象内部属性相互依赖。
优点
分离构建过程和表示,使得构建过程更加灵活,可以构建不同的表示。
可以更好地控制构建过程,隐藏具体构建细节。
代码复用性高,可以在不同的构建过程中重复使用相同的建造者。
缺点
如果产品的属性较少,建造者模式可能会导致代码冗余。
增加了系统的类和对象数量。
原型模式
原型模式(Prototype Pattern)
- 概述:
原型模式(Prototype Pattern)是创建型模式,用于当创建对象的成本高时,通过复制一个现有对象来创建一个新对象,从而避免创建一个新对象的 。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
- 结构:
- 抽象原型类:定义了一个克隆自身的接口,即规定了具体原型对象必须实现的clone()方法。
- 具体原型类:实现抽象原型类的clone()方法,它是可被复制的对象。
- 客户端类:使用具体原型类中的clone()方法来克隆新的对象。
- 实现:
原型模式的克隆分为:浅克隆和深克隆。
- 浅克隆创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,任指向原有属性所指向的对象的内存地址。
- 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不会指向原有对象地址。
- 注意:Java中的Object类提供了clone()方法,该方法返回一个对象,该对象是当前对象的一个副本。
- 浅克隆:调用Object类的clone()方法。
- 深克隆:
- 实现Cloneable接口。
- 重写clone()方法。
- 在clone()方法中,使用super.clone()方法创建一个新对象,然后将当前对象的属性值复制到新对象中。
- 如果属性是引用类型,需要递归调用clone()方法。
在Java中,原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而不是通过新建类实例的方式。在实现原型模式时,我们通常会使用clone()
方法,而复制对象时就会涉及到浅克隆(Shallow Clone)和深克隆(Deep Clone)的概念。
浅克隆(Shallow Clone)
浅克隆是指当复制一个对象时,对于基本数据类型的成员变量,会直接复制其值;而对于引用类型的成员变量,则只复制其引用地址(也就是内存地址),而不会复制引用所指向的实际对象。因此,在浅克隆中,原始对象和克隆对象中的引用类型成员变量将指向同一个对象。
在Java中,通过实现Cloneable
接口并重写Object
类的clone()
方法来实现浅克隆。Object
类的clone()
方法默认实现就是浅克隆。
示例代码:
class Address { private String city; public Address(String city) { this.city = city; } } class Person implements Cloneable { private String name; private Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
Address address = new Address("Beijing"); Person p1 = new Person("Tom", address); Person p2 = (Person) p1.clone();
System.out.println(p1.getAddress() == p2.getAddress());
|
深克隆(Deep Clone)
深克隆是指复制对象时,不仅复制对象本身,而且递归复制对象所引用的其他对象。因此,深克隆会复制整个对象网络,使得原始对象和克隆对象之间互不影响,它们拥有各自独立的内存空间。
实现深克隆的方式有多种:
- 重写
clone()
方法,并在其中对引用类型进行递归克隆(需要引用类型也实现Cloneable
接口并重写clone()
方法)。
- 使用序列化(Serialization)和反序列化(Deserialization)来实现深克隆。将对象写入到字节流中,然后再从字节流中读取回来,这样会创建一个完全独立的副本。
示例代码(通过重写clone方法实现深克隆):class Address implements Cloneable { private String city; public Address(String city) { this.city = city; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Person implements Cloneable { private String name; private Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); cloned.address = (Address) address.clone(); return cloned; } }
Address address = new Address("Beijing"); Person p1 = new Person("Tom", address); Person p2 = (Person) p1.clone();
System.out.println(p1.getAddress() == p2.getAddress());
|
序列化实现深克隆
如果引用类型嵌套层次很深,或者引用类型没有实现Cloneable
接口,则可以通过序列化的方式实现深克隆。需要确保所有涉及的类都是可序列化的(实现Serializable
接口)。
示例代码:
import java.io.*; class Address implements Serializable { private String city; public Address(String city) { this.city = city; } } class Person implements Serializable { private String name; private Address address; public Person(String name, Address address) { this.name = name; this.address = address; } public Person 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 (Person) ois.readObject(); } }
Address address = new Address("Beijing"); Person p1 = new Person("Tom", address); Person p2 = p1.deepClone(); System.out.println(p1.getAddress() == p2.getAddress());
|
总结
- 浅克隆:复制基本数据类型的值,对于引用类型,只复制引用地址,因此原对象和克隆对象会共享引用类型的成员变量。修改其中一个对象的引用类型成员变量,另一个对象也会受到影响。
- 深克隆:复制基本数据类型的值,同时递归复制引用类型的对象。因此,原对象和克隆对象之间完全独立,互不影响。
在实际应用中,选择浅克隆还是深克隆取决于具体需求。如果对象的引用类型成员变量在创建后不会改变,或者你希望共享这些对象,那么浅克隆就足够了,并且效率更高。如果需要完全独立的副本,则应该使用深克隆。但要注意深克隆可能带来的性能问题,特别是在对象图很大的情况下。
关键区别总结
特性 |
浅克隆 |
深克隆 |
引用类型复制 |
复制内存地址(共享对象) |
递归复制实际对象(完全独立) |
修改影响 |
修改引用类型成员会影响所有副本 |
修改引用类型成员不影响其他副本 |
实现复杂度 |
简单(默认clone() ) |
复杂(需递归处理所有引用类型) |
性能 |
高效(不创建新对象) |
较低(递归创建新对象) |
适用场景 |
引用类型不可变或无需隔离时 |
引用类型需完全隔离时 |
注意事项
String
的特殊性:
虽然String
是引用类型,但其不可变性(Immutable)使得浅克隆中修改String
值会创建新对象,不会影响原对象(行为类似深克隆)。但其他引用类型(如自定义类)仍需谨慎。
- 深克隆的替代方案:
序列化(Serializable
)是另一种深克隆实现,但要求所有涉及的对象都实现Serializable
接口:public static <T> T deepClone(T obj) throws IOException, ClassNotFoundException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(obj); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (T) ois.readObject(); }
|
单例模式
Singleton(单例模式)
意图:
确保一个类只有一个实例,并提供一个全局访问点来访问该实例
注意事项
- 线程安全:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成实例被多次创建。
- 延迟初始化:实例在第一次调用 getInstance() 方法时创建。
- 序列化和反序列化:重写 readResolve 方法以确保反序列化时不会创建新的实例。
- 反射攻击:在构造函数中添加防护代码,防止通过反射创建新实例。
- 类加载器问题:注意复杂类加载环境可能导致的多个实例问题。
- 结构
单例模式包含以下几个主要角色:
- 单例类:包含单例实例的类,通常将构造函数声明为私有。
- 静态成员变量:用于存储单例实例的静态成员变量。
- 获取实例方法:静态方法,用于获取单例实例。
- 私有构造函数:防止外部直接实例化单例类。
- 线程安全处理:确保在多线程环境下单例实例的创建是安全的。
单例模式的实现
- 单例设计模式分类两种:
- 饿汉式:类加载就会导致该单例实例对象被创建,适用于单线程环境。
- 懒汉式:类加载不会导致该单例实例对象被创建,而是首次使用该对象时才会创建,适用于多线程环境。
饿汉式——静态成员变量
public class Singleton{ private Singleton(){}
private static Singleton instance =new Singleton();
public static Singleton getInstance(){ return instance; } }
|
测试类
public calss Client{ public static void main(String[] args) { Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); if(instance==instance1){ System.out.println("两个对象是同一个对象"); }else{ System.out.println("两个对象不是同一个对象"); } } }
|
饿汉式——静态代码块
public class Singleton{ private Singleton(){}
private static Singleton instance;
static{ instance = new Singleton(); }
public static Singleton getInstance(){ return instance; } }
|
饿汉式——枚举
- 原由:枚举类实现单例模式是极力推荐的单例实现模式,因为枚举类型是线程安全的,并且只会加载一次。而且枚举类型是所用单例实现中唯一不会被破坏的单例实现模式。
public enum Singleton{ INSTANCE; }
|
测试类
public class Client{ public static void main(String[] args){ Singleton instance = Singleton.INSTANCE; Singleton instance1 = Singleton.INSTANCE; System.out.println(instance==instance1); } }
|
- 总结:
优点: 内存中只有一个实例,减少内存开销,尤其是频繁创建和销毁实例时(如管理学院首页页面缓存)。
避免资源的多重占用(如写文件操作)。
缺点:饿汉式在类加载时就创建了实例对象,可能造成内存的浪费。
懒汉式——线程不安全情况
public class Singleton{ private Singleton(){}
private static Singleton instance;
public static Singleton getInstance(){ if(instance==null){ instance = new Singleton(); } return instance; } }
|
测试类
public class Client{ public static void main(String[] args){ Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance==instance1); } }
|
懒汉式——线程安全情况
public class Singleton{ private Singleton(){}
private static Singleton instance;
public static synchronized Singleton getInstance(){ if(instance==null){ instance = new Singleton(); } return instance; } }
|
懒汉式——双重检查锁
- 优势:解决了单例、性能、线程安全问题。因为在多线程的情况下,可能会出现空指针问题,出现问题的原因是JVM在实例化对象的时候会进行优化和指令重新排序操作。可以使用 volatile 关键字修饰成员变量和静态成员变量,防止指令重排序。
public class Singleton{ private Singleton(){}
public static volatile Singleton instance;
public static Singleton getInstance(){ if(instance==null){ synchronized (Singleton.class){ if(instance==null){ instance=new Singleton(); } } } return instance; } }
|
懒汉式——静态内部类
- 原由:静态内部类单里模式由内部类创建,由于JVM在加载外部类的过程中,是不会加载静态内部类的,只有内部类的属性、方法被调用时才会被加载,并初始化其静态资源,静态资源由于被static修饰,因此只会被创建一次,并且创建时是线程安全的。
public class Singleton{ private Singleton(){} public static class SingletonHolder{ private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.INSTANCE; } }
|
测试类
public class Client{ public static void main(String[] args){ Singleton instance = Singleton.getInstance(); Singleton instance1 = Singleton.getInstance(); System.out.println(instance==instance1); } } 结果为ture
|
- 说明:第一次加载Singleton类时并不会初始化instance,只有第一次调用getInstance()方法时,虚拟机加载SingletonHolder类并初始化instance,并且instance是static的,因此只会被创建一次。这样不仅能保证线程的安全性,还能保证Singleton类的唯一性。
存在的问题——破坏单例模式
破会啊单例模式:使上面定义的单例类可以创建多个对象,美剧方式除外,有两种方式:序列化和反射。
例子:
- 序列化与反序列化
public class Singleton implements Serializable{ private Singleton(){} public static class SingletonHolder{ private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.INSTANCE; } }
|
测试类:
public class Client{ public static void main(String[] args) throws Exception { readObjectFromFile(); readObjectF romFile(); } public static void readObjectFromFile() throw Exception{ ObjectInputStream ois =new ObjectInputStream(new FileInputStream("C:\\Users\\j.txt")); Singleton instance=(Singleton) ois.readObject(); System.out.println(instance); ois.close(); } public static void writeObject2File() throws Exception{ Singleton instance = Singleton.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\j.txt")); oos.writeObject(instance); oos.close(); } }
|
- 反射
public class Client{ public static void main(String[] args) throws Exception{ Class class =Singleton.class; Constructor constructor = class.getDeclaredConstructor(); constructor.setAccessible(true); Singleton instance1 = (Singleton) constructor.newInstance(); Singleton instance2 = (Singleton) constructor.newInstance(); System.out.println(instance1 == instance2); } }
|
上述问题的解决
1.序列化与反序列化破坏单例模式的解决方法:
- 在Singleton类中添加readResolve()方法,在序列化时被反射调用,如果定义了这个方法,就返回这个方法的值,反之,就返回新new出来的对象。
public class Singleton implements Serializable{ private Singleton(){} public static class SingletonHolder{ private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.INSTANCE; } public Object readResolve(){ return SingletonHolder.INSTANCE; } }
|
测试类:public class Client{ public static void main(String[] args) throws Exception { readObjectFromFile(); readObjectF romFile(); } public static void readObjectFromFile() throw Exception{ ObjectInputStream ois =new ObjectInputStream(new FileInputStream("C:\\Users\\j.txt")); Singleton instance=(Singleton) ois.readObject(); System.out.println(instance); ois.close(); } public static void writeObject2File() throws Exception{ Singleton instance = Singleton.getInstance(); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\j.txt")); oos.writeObject(instance); oos.close(); } }
|
2.反射破坏单例模式的解决方法:public class Singleton { private static boolean flag = false;
private Singleton(){
synchronized (Singleton.class) { if (flag) { throw new RuntimeException("不能创建多个对象"); } flag = true; } }
public static class SingletonHolder{ private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.INSTANCE; } }
|
public class Client{ public static void main(String[] args) throws Exception{ Class class =Singleton.class; Constructor constructor = class.getDeclaredConstructor(); constructor.setAccessible(true); Singleton instance1 = (Singleton) constructor.newInstance(); Singleton instance2 = (Singleton) constructor.newInstance(); System.out.println(instance1 == instance2); } }
|
工厂模式
工厂模式(Factory Pattern)
在Java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,又假如我们要更换对象,就要将所有new对象的地方都要需改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只要和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂中更换对象即可,达到了与对象解耦的目的。所以说,工厂模式最大的优点是:减低耦合。
工厂模式类型
- 简单工厂模式(Simple Factory Pattern):不属于23中设计模式,因为违反了开闭原则
简单工厂模式不是一个正式的设计模式,但它是工厂模式的基础。它使用一个单独的工厂类来创建不同的对象,根据传入的参数决定创建哪种类型的对象。
- 工厂方法模式(Factory Method Pattern):
工厂方法模式定义了一个创建对象的接口,但由子类决定实例化哪个类。工厂方法将对象的创建延迟到子类。
- 抽象工厂模式(Abstract Factory Pattern):
抽象工厂模式提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
简单工厂模式:
- 结构:
- 抽象产品:定义了产品的规范,描述了产品的主要特征和功能
- 具体产品:实现了抽象产品接口,定义了产品的具体功能(实现或者继承了抽象产品的子类)
- 具体工厂:提供了创建产品的方法,调用者通过该方法来创建产品
- 步骤 1:
创建一个接口:Shape.javapublic interface Shape{ void Shape(); }
|
- 步骤 2:
创建实现接口的实体类。
Rectangle.javapublic class Restangle implements Shape{ @Override public void Shape(){ System.out.println("Rectangle"); } }
|
Square.java
public class Square implements Shape{ @Override public void Shape(){ System.out.println("Square"); } }
|
- 步骤 3:
创建一个工厂,生成基于给定信息的实体类的对象。
ShapeFactory.javapublic calss ShapeFactory{
public Shape getShape(String shapeType){ if(shapeTuype==null){ return null; } if(shapeType.equalsIgnoreCase("Rectangle")){ return new Restangle(); } if(shapeType.equalsIgnoreCase("Square")){ return new Square(); }
} }
|
- 步骤4:
使用该工厂,通过传递类型信息来获取实体类对象
FactoryPatternDemo.javapublic class FactoryPatternDemo{ public static void main(String[] args){ ShapeFactory shapeFactory =new ShapeFactory(); Shape shape1=shapeFactory.getShape("Rectangle"); shape1.Shape();
} }
|
工厂方法模式
结构:
工厂模式主要包含一下几个主要角色:
抽象产品:定义产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了该产品对象的共同方法。
具体产品:实现了抽象产品接口,定义了具体产品的特定行为和属性。
抽象工厂:声明了创建产品的抽象方法,可以是接口或者抽象类,它可以有多个方法用于创建不同类型的产品。
具体工厂:实现了抽象工厂接口,定义了创建具体产品的方法,并返回具体产品对象。
抽象工厂:
public interface CoffeeFactory{ Coffee createCoffee(); }
|
具体工厂:
public class AmericanCoffeeFactory implements CoffeeFactory{ @Override public Coffee createCoffee(){ return new AmericanCoffee(); }
}
|
public class LatteCoffeeFactory implements CoffeeFactory{ @Override public Coffee createCoffee(){ return new LatteCoffee(); } }
|
抽象产品:
public abstract class Coffee{ public abstract String getName(); public void addMilk(){ System.out.println("加奶"); } public void addSugar(){ System.out.println("加糖"); }
}
|
具体产品:
public class AmericanCoffee extends Coffee{ public String getName(){ return "AmericanCoffee"; } }
|
public class LatteCoffee extends Coffee{ public String getName(){ return "LatteCoffee"; } }
|
中间依赖类:
public class CoffeeStore{
private CoffeeFactory factory;
public void SetFactory(CoffeeFactory factory){ this.factory=factory; } public Coffee OrderCoffee(){ Coffee coffee=factory.CreateCoffee(); coffee.addMilk(); coffee.addSugar(); return coffee; }
}
|
Client 测试类
public class Client{ public static void main(String[] args){ CoffeeStore store=new CoffeeStore(); CoffeeFactory factory=new AmericanCoffeeFactory(); store.SetFactory(factory); Coffee coffee=store.OrderCoffee();
System.out.println(coffee.getName()); } }
|
工厂方法模式优势:
解耦:客户端与具体产品类解耦,调用者只需要知道对象的名称即可创建对象。
扩展性:添加新产品只需新增具体工厂和产品类
单一职责:每个工厂只负责创建一种产品
开闭原则:对扩展开放,对修改关闭
- 每次增加一个产品时,都需要增加一个具体类和对应的工厂,使系统中类的数量成倍增加,增加了系统的复杂度和具体类的依赖。
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定具体实现类。通过使用抽象工厂模式,可以将客户端与具体产品的创建过程解耦,使得客户端可以通过工厂接口来创建一族产品。
抽象工厂模式通常涉及一族相关的产品,每个具体工厂类负责创建该族中的具体产品。客户端通过使用抽象工厂接口来创建产品对象,而不需要直接使用具体产品的实现类。
结构:
抽象工厂模式的主要角色如下:
抽象工厂:提供了创建产品的接口,它包含了多个创建产品的方法,可以创建多个不同等级的产品。
具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
抽象产品:定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
优点:
确保同一产品族的对象一起工作。
客户端不需要知道每个对象的具体类,简化了代码。
缺点:
扩展产品族非常困难。增加一个新的产品族需要修改抽象工厂和所有具体工厂的代码。
适用场景:
1.当系统需要创建多个相关或依赖的对象,而不需要指定具体类时。
2.当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、电冰箱、空调等。
3.系统中有多个产品族,而系统只消费其中的一族产品。
4.当一个产品族中的多个对象被设计成一起工作时,需要确保客户端代码不会依赖于具体的产品类。
抽象工厂:
public interface DessertFactory { Coffee createCoffee(); Dessert createDessert(); }
|
具体工厂:
public class AmerricanDessertFactory implements DessertFactory {
@Override public Coffee createCoffee() { return new AmericanCoffee(); }
@Override public Dessert createDessert() { return new MatchMousse(); } }
|
public class ItalyDessertFactory implements DessertFactory{
@Override public Coffee createCoffee() { return new LatteCoffee(); }
@Override public Dessert createDessert() { return new Trimisu(); } }
|
- 抽象产品:
public abstract class Dessert { public abstract void show(); }
|
public abstract class Coffee{ public abstract String getName(); public void addMilk(){ System.out.println("加奶"); } public void addSugar(){ System.out.println("加糖"); }
}
|
- 具体产品:
public class Trimisu extends Dessert{ @Override public void show() { System.out.println("Trimisu"); } }
|
public class MatchMousse extends Dessert{ @Override public void show() { System.out.println("MatchMousse"); } }
|
public class AmericanCoffee extends Coffee{ public String getName(){ return "AmericanCoffee"; } }
|
public class LatteCoffee extends Coffee{ public String getName(){ return "LatteCoffee"; } }
|
- 测试类:
public class Client { public static void main(String[] args) { ItalyDessertFactory factory=new ItalyDessertFactory(); Coffee coffee=factory.createCoffee(); Dessert dessert=factory.createDessert();
System.out.println(coffee.getName()); dessert.show();
} }
|
模式扩展:
简单工厂+配置文件接触耦合:
可以通过工厂模式+配置文件的方式可解除工厂对象和产品对象的耦合,在工厂类中加载配置文件的全类名,并创建对象进行存储,客户端如果需要对象,直接进行获取即可。
public class DessertFactory {
public static Dessert createDessert(String type){
try {
//加载配置文件
Properties properties=new Properties();
properties.load(new FileInputStream("bean.properties"));
//获取type全限定类名
String className=properties.getProperty(type);
//通过反射创建对象
return (Dessert) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Coffee createCoffee(String type){
try {
//加载配置文件
Properties properties=new Properties();
properties.load(new FileInputStream("bean.properties"));
//获取type全限定类名
String className=properties.getProperty(type);
//通过反射创建对象
return (Coffee) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
//测试类
public class Client {
public static void main(String[] args) {
//创建的是意大利风味甜品工厂对象
ItalyDessertFactory factory=new ItalyDessertFactory();
//再从工厂里面获取所需要的产品
Coffee coffee=factory.createCoffee();
Dessert dessert=factory.createDessert();
System.out.println(coffee.getName());
dessert.show();
//通过简单工厂+配置文件的方式创建对象
Coffee coffee1=DessertFactory.createCoffee("latte");
Dessert dessert1=DessertFactory.createDessert("trimisu");
System.out.println(coffee1.getName());
dessert1.show();
}
}