Spring 5 设计模式 - Creational
我们都知道怎么创建一个新对象:
Account account = new Account();
有时候,这样写不太合适,因为这样硬编码,导致以后不容易修改对象。使用creational设计模式可以提高创建对象的灵活性。
Factory
Factory设计模式也叫Factory method设计模式。使用该模式,你可以得到对象,而且还没有暴露底层逻辑。它使用一个通用的接口或者抽象类给调用者分配对象,这样就隐藏了实现逻辑。通过工厂模式,调用者可以方便地增加、管理和销毁对象。
工厂模式带来的好处:
- 通过使用接口,促进了松耦合
- 可以在运行时得到实现了接口的对象
- 对象生存期由工厂管理
Spring的工厂模式
Spring使用工厂模式实现Spring容器。Spring容器基于工厂模式增加bean,也管理每个bean的生存期。BeanFactory和ApplicationContext是工厂接口,Spring有很多实现类。
简单的例子
有两个类SavingAccount和CurrentAccount都实现了Account接口。所以,你可以增加一个工厂类,其中的一个方法可以接受一个或者多个参数返回Account类型。这个方法就是工厂方法。根据传入工厂方法的参数,可以选择要实例化的子类:
public interface Account {
void accountType();
}
public class SavingAccount implements Account{
@Override
public void accountType() {
System.out.println("SAVING ACCOUNT");
}
}
public class CurrentAccount implements Account {
@Override
public void accountType() {
System.out.println("CURRENT ACCOUNT");
}
}
可以这样实现工厂类:
public class AccountFactory {
final String CURRENT_ACCOUNT = "CURRENT";
final String SAVING_ACCOUNT = "SAVING";
public Account getAccount(String accountType){
if(CURRENT_ACCOUNT.equals(accountType)) {
return new CurrentAccount();
}
else if(SAVING_ACCOUNT.equals(accountType)){
return new SavingAccount();
}
return null;
}
}
Abstract factory
这是一个比工厂模式高级的设计模式。使用抽象工厂模式,你只定义一个接口或者抽象类来增加有关的依赖对象,而不指定具体子类。所以,抽象工厂返回的是类的工厂。比如,我们有一些工厂类,把这些工厂放到一个工厂里,就是说有了一个工厂的工厂。
抽象工厂带来的好处:
- 在组件族之间提供了松耦合
- 提供了对象构造时的一致性
Spring中的Abstract factory
FactoryBean接口就是基于抽象工厂设计模式的。Spring提供了它的很多实现,比如ProxyFactoryBean、JndiFactoryBean、LocalSessionFactoryBean和LocalContainerEntityManagerFactoryBean等。它有助于构造依赖关系比较复杂的bean,也有助于构造可变化的或者依赖配置的bean。
比如,LocalSessionFactoryBean用来获取与hibernate configuration相关的bean的引用。它是数据源相关的配置,在你从SessionFactory获取对象前它就应该应用了。你可以把getObject()返回的结果注入其他属性。
简单的例子
public interface Bank {
void bankName();
}
public class ICICIBank implements Bank {
@Override
public void bankName() {
System.out.println("ICICI Bank Ltd.");
}
}
public class YesBank implements Bank{
@Override
public void bankName() {
System.out.println("Yes Bank Pvt. Ltd.");
}
}
下面是工厂类
public abstract class AbstractFactory {
abstract Bank getBank(String bankName);
abstract Account getAccount(String accountType);
}
public class BankFactory extends AbstractFactory {
final String ICICI_BANK = "ICICI";
final String YES_BANK = "YES";
@Override
Bank getBank(String bankName) {
if(ICICI_BANK.equalsIgnoreCase(bankName)) {
return new ICICIBank();
}
else if(YES_BANK.equalsIgnoreCase(bankName)) {
return new YesBank();
}
return null;
}
@Override
Account getAccount(String accountType) {
return null;
}
}
public class FactoryProducer {
final static String BANK = "BANK";
final static String ACCOUNT = "ACCOUNT";
public static AbstractFactory getFactory(String factory) {
if(BANK.equalsIgnoreCase(factory)) {
return new BankFactory();
}
else if(ACCOUNT.equalsIgnoreCase(factory)) {
return new AccountFactory();
}
return null;
}
}
测试代码
public class FactoryPatterMain {
public static void main(String[] args) {
AccountFactory accountFactory = new AccountFactory();
Account savingAccount = accountFactory.getAccount("SAVING");
savingAccount.accountType();
Account currentAccount = accountFactory.getAccount("CURRENT");
currentAccount.accountType();
}
}
Singleton
带来的好处:
- 可以控制对关键类(一般是比较重的对象)的访问,比如数据库连接池
- 节省堆内存
- 在多线程环境里很高效
- 更灵活。因为控制了实例化的过程,所以更方便修改
- 低延迟
Spring 中的应用
Singleton scoped bean就使用了单例模式。此时,每个容器里一个bean的实例。
public class SingletonClass {
private static final SingletonClass INSTANCE = new SingletonClass();
private SingletonClass() {}
public static SingletonClass getInstance() {
return INSTANCE;
}
}
Prototype
该模式使用对象的clone方法增加对象。如果直接增加对象比较费时,可以用原型模式。比如,通过费时的数据库操作,我们增加了一个对象。然后缓存该对象,在下一次请求时,返回它的clone,如果需要,可以更新数据库,这样减少了数据库操作。
带来的好处:
- 减少了子类
- 在运行时增加和删除对象
简单的例子
先增加抽象的Account类,再增加具体的子类
public abstract class Account implements Cloneable{
abstract public void accountType();
public Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
public class CurrentAccount extends Account {
@Override
public void accountType() {
System.out.println("CURRENT ACCOUNT");
}
}
public class SavingAccount extends Account {
@Override
public void accountType() {
System.out.println("SAVING ACCOUNT");
}
}
再增加AccountCache类,使用HashMap保存帐号对象,请求的时候返回对象的克隆
public class AccountCache {
public static Map<String, Account> accountCacheMap = new HashMap<>();
static{
Account currentAccount = new CurrentAccount();
Account savingAccount = new SavingAccount();
accountCacheMap.put("SAVING", savingAccount);
accountCacheMap.put("CURRENT", currentAccount);
}
}
下来是测试代码
public class PrototypePatternMain {
public static void main(String[] args) {
Account currentAccount = (Account)
AccountCache.accountCacheMap.get("CURRENT").clone();
currentAccount.accountType();
Account savingAccount = (Account)
AccountCache.accountCacheMap.get("SAVING") .clone();
savingAccount.accountType();
}
}
Builder
Builder设计模式一步步地构造复杂对象,最终返回完整的对象。
Spring中的Builder
Spring不少地方使用了Builder模式,比如:EmbeddedDatabaseBuilder、AuthenticationManagerBuilder、UriComponentsBuilder、BeanDefinitionBuilder等。
简单的例子
public class Account {
private String accountName;
private Long accountNumber;
private String accountHolder;
private double balance;
private String type;
private double interest;
private Account(AccountBuilder accountBuilder) {
super();
this.accountName = accountBuilder.accountName;
this.accountNumber = accountBuilder.accountNumber;
this.accountHolder = accountBuilder.accountHolder;
this.balance = accountBuilder.balance;
this.type = accountBuilder.type;
this.interest = accountBuilder.interest;
}
public static class AccountBuilder {
private final String accountName;
private final Long accountNumber;
private final String accountHolder;
private double balance;
private String type;
private double interest;
public AccountBuilder(String accountName,
String accountHolder, Long accountNumber) {
this.accountName = accountName;
this.accountHolder = accountHolder;
this.accountNumber = accountNumber;
}
public AccountBuilder balance(double balance) {
this.balance = balance;
return this;
}
public AccountBuilder type(String type) {
this.type = type;
return this;
}
public AccountBuilder interest(double interest) {
this.interest = interest;
return this;
}
public Account build() {
Account user = new Account(this);
return user;
}
}
public String toString() {
return "Account [accountName=" + accountName + ", accountNumber=" + accountNumber +
", accountHolder=" + accountHolder + ", balance=" + balance + ", type="
+ type + ", interest=" + interest + "]";
}
}
测试代码
public class AccountBuilderTest {
public static void main(String[] args) {
Account account = new Account.AccountBuilder("SavingAccount", "Dinesh Rajput", 1111l)
.balance(38458.32)
.interest(4.5)
.type("SAVING")
.build();
System.out.println(account);
}
}