设计模式-类创建

基于接口编程

程序 以 类 为 单位, 组织开发。

类,本身就是一种抽象,抽象了 真实存在 的 对象 。这就像 蛋糕模具,模具总是完整的,但做出来的蛋糕可能是有残角的。我们定义类,就是定义了一个完整的模具,实例化的对象可能属性值为空,或是 方法从未被使用过。

类 的 特性:
1. 封装-访问控制:每个事物有自己的边界、内在关联
2. 抽象 -接口、抽象类、函数、宽泛命名、添加注释:抽象简化问题,只关注功能不关心实现细节
3. 继承+多态-重写、实现,超出四层用 -> 组合,扁平化

接口 定义了 功能。飞翔 接口。其 实现类 大雁会飞,飞蛾会飞。当一个接口有不止一个实现类时,接口代替类,可以 快速做类的变更。

WildGoose wildGoose =new WildGoose();
// 大雁飞
wildGoose.fly();
->
Moth moth =new Moth();
// 飞蛾飞
moth.fly();


Fly fly =new WildGoose();
// 大雁飞
fly.fly();
->
Fly fly =new Moth();
// 飞蛾飞
fly.fly();

接口与抽象类

接口 表达 功能。自上而下 设计。

抽象类 表达 有继承关系,但需要 抽象方法。自下而上 多态。

        抽象类定义一致的控制逻辑

一定要定义接口吗

MVC 框架 Service 接口还是很有用的,刚创建可能用处不大,不要给以后埋坑。

service层的接口有什么用? - 知乎 (zhihu.com)

接口多个实现类时的问题

1. 把类的创建耦合在你的业务逻辑中就不好维护了,得抽离出来。

2. 或是你该做的灵活一点,根据业务请求 决定 使用 哪个实现类。

3. 每次需要类时就创建一个类,类创建和销毁操作 导致 资源浪费明显。

模式

单例模式


1. 饿汉式


- private static final
- public static

不常用


2. 懒汉式

```java
//懒汉式-- 实例方法 调用时,类进行实例化。   synchronized,不支持高并发  
private static IdGenerator lazyInstance;  
  
public static synchronized IdGenerator getLazyInstance() {  
    if (lazyInstance == null) {  
        lazyInstance = new IdGenerator();  
    }  
    return lazyInstance;  
}

// 调用
IdGenerator.getLazyInstance();
```

3. 双重检测

```java
//双重检测,实例化后不会再进入加锁逻辑  
//高版本的JDK 把对象 new 操作和初始化操作设计为原子操作,能禁止指令重排  
// volatile 关键字则保证了指令的顺序性(禁止指令重排)和对象初始化的正确性(指令重排引起)。  
private volatile static IdGenerator doubleCheckInstance; //DCL(双重检测锁)  
  
public static IdGenerator getDoubleCheckInstance() {  
    if (doubleCheckInstance == null) {  
        // 加锁保证变量的可见性和线程安全性  
        // 加类锁  
        synchronized (IdGenerator.class) {  
            if (doubleCheckInstance == null) {  
                doubleCheckInstance = new IdGenerator();  
            }  
        }  
    }  
    return doubleCheckInstance;  
}

// 调用
IdGenerator.getDoubleCheckInstance();
```


4. 静态内部类

- insance 的唯一性、创建过程的线程安全性,都由 JVM 来保证
- private static class
- private static final

```java
// IdGenerator 类内
/**  
 * 静态内部类,insance 的唯一性、创建过程的线程安全性,都由 JVM 来保证  
 * @return  
 */  
public static IdGenerator getStaticInstance() {  
    return SingletonHolder.instance;  
}  
  
/**  
 * 内部类的方式,实现单例懒加载  
 * 因为需要方法到 内部类的 static 变量,所以才声明内部类为 static 类  
 * 为了避免滥用内部类,内部类 用 private 修饰  
 */  
private static class SingletonHolder {  
    /**  
     * 类的 static变量(必须是 非基本/字符串类型 或者 非final修饰)在初始化时赋值,JVM确保初始化时的线程安全性  
     *  
     * 避免this引用逃逸:  
     *  1. 在构造函数中避免启动新线程或将"this"引用传递给其他对象。  
     *  2. 避免在构造函数中调用外部类或静态方法,并将"this"引用传递给它们。  
     *  3. 将构造函数声明为私有,并使用工厂方法来创建对象,确保对象完全构造完成后再对外暴露。  
     * 如果能避免this引用逃逸,那final修饰的变量可以确保只被赋值一次  
     */  
    public static final IdGenerator instance = new IdGenerator();  
  
}

// 调用
IdGenerator.getStaticInstance();
```


5. 枚举


- public enum
- INSTANCE;

```java
/**  
 * 单例,枚举实现
 */  
public enum IdGeneratorEnum {  
    INSTANCE;  
}

// 调用
IdGeneratorEnum.INSTANCE;
```

工厂模式

1. 静态工厂

A-A.1
静态工厂在于 两级 A-A.1

2. 工厂方法

A.1-B.1/B.2
工厂方法在于 B可选为 B.1/B.2

组合通过Map预存所有来实现
```java
// ElfBlacksmith 初始化
static {  
  // EnumMap,一个map, key 为 枚举类型  
  ELFARSENAL = new EnumMap<>(WeaponType.class);  
  Arrays.stream(WeaponType.values()).forEach(type -> ELFARSENAL.put(type, new ElfWeapon(type)));  
}

// 使用 ElfBlacksmith#manufactureWeapon
ELFARSENAL.get(weaponType);
```

3. 抽象工厂

A-A.1-B.1 ; A-A.2-B.2
抽象工厂在于 三级A-A.1-B.1

一级静态工厂,KingdomType 实现
```java
// 声明
@RequiredArgsConstructor  
@Getter  
public enum KingdomType {  
  ELF(ElfKingdomFactory::new),  
  ORC(OrcKingdomFactory::new);  
  
  private final Supplier<KingdomFactory> constructor;  
}

// 使用 关键字获取实例
(Kingdom.FactoryMaker.KingdomType kingdomType)kingdomType.getConstructor().get();
```

高分作业spring-beans

Java Spring 框架 spring-beans 模块对 这个问题做了好的解答。Spring这个底层框架帮你管理 类创建和类间依赖。

Spring解决 类创建和业务代码耦合问题:

1. 引入Spring框架

2. 注解 声明 类 加入Spring管理

3. 注解 引用 类对象

Spring解决 一个接口多个实现类问题:

1. 引入Spring框架

2. 在每个实现类 上 声明 类 加入Spring管理

3.  注解,用Map(实现类名首字母小写,实现类) .get(实现类名首字母小写)  获取实现类

Spring解决 类 频繁创建和销毁的资源浪费问题:

Spring创建的类默认是 单例类

看实现

基于 spring-beans-5.3.22.jar

 Factory,工厂,一种创建类的设计模式,Spring 把 他管理的 类 叫做 Bean。所以有 顶层接口 BeanFactory。 

// 查找 Bean 声明
// org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
/**
 * Build and validate a configuration model based on the registry of
 * {@link Configuration} classes.
 */
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
}

// 创建Bean
// org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

/**
 * The name of the currently created bean, for implicit dependency registration
 * on getBean etc invocations triggered from a user-specified Supplier callback.
 */
private final NamedThreadLocal<String> currentlyCreatedBean = new NamedThreadLocal<>("Currently created bean");


/**
* Actually create the specified bean. Pre-creation processing has already happened
* at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks.
* <p>Differentiates between default bean instantiation, use of a
* factory method, and autowiring a constructor.
* @param beanName the name of the bean
* @param mbd the merged bean definition for the bean
* @param args explicit arguments to use for constructor or factory method invocation
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
* @see #instantiateBean // 实例化Bean
* @see #instantiateUsingFactoryMethod // 使用工厂方法 实例化 BeanWrapper
* @see #autowireConstructor   // 反射创建Bean
*/ 
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 
throws BeanCreationException {
    // Instantiate the bean. 实例化Bean
	BeanWrapper instanceWrapper = = createBeanInstance(beanName, mbd, args);
    // Bean 依赖处理
    populateBean(beanName, mbd, instanceWrapper);
    exposedObject = initializeBean(beanName, exposedObject, mbd);
}

/**
 * Create a new instance for the specified bean, using an appropriate instantiation strategy:
 * factory method, constructor autowiring, or simple instantiation.
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @param args explicit arguments to use for constructor or factory method invocation
 * @return a BeanWrapper for the new instance
 * @see #obtainFromSupplier // 存储创建的Bean
 * @see #instantiateUsingFactoryMethod
 * @see #autowireConstructor
 * @see #instantiateBean
 */
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
	    return obtainFromSupplier(instanceSupplier, beanName);
    }
    if (mbd.getFactoryMethodName() != null) {
	    return instantiateUsingFactoryMethod(beanName, mbd, args);
    }
    if (autowireNecessary) {
	    return autowireConstructor(beanName, mbd, null, null);
    }
    else {
	    return instantiateBean(beanName, mbd);
    }

}

/**
 * Create a new AbstractAutowireCapableBeanFactory.
 */
public AbstractAutowireCapableBeanFactory() {
    // Bean 创建策略
	if (NativeDetector.inNativeImage()) {
        // nstantiate a class using the given constructor.
		this.instantiationStrategy = new SimpleInstantiationStrategy();
	}
	else {
        // generate CGLIB subclass.
		this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
	}
}

/**
 * Instantiate the given bean using its default constructor.
 * @param beanName the name of the bean
 * @param mbd the bean definition for the bean
 * @return a BeanWrapper for the new instance
 */
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
    // 选用Bean 创建策略
    // 工厂方法模式 创建Bean
    Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
    BeanWrapper bw = new BeanWrapperImpl(beanInstance);
    initBeanWrapper(bw);
}

/**
 * Instantiate the bean using a named factory method. The method may be static, if the
 * bean definition parameter specifies a class, rather than a "factory-bean", or
 * an instance variable on a factory object itself configured using Dependency Injection.
 * <p>Implementation requires iterating over the static or instance methods with the
 * name specified in the RootBeanDefinition (the method may be overloaded) and trying
 * to match with the parameters. We don't have the types attached to constructor args,
 * so trial and error is the only way to go here. The explicitArgs array may contain
 * argument values passed in programmatically via the corresponding getBean method.
 * @param beanName the name of the bean
 * @param mbd the merged bean definition for the bean
 * @param explicitArgs argument values passed in programmatically via the getBean
 * method, or {@code null} if none (-> use constructor argument values from bean definition)
 * @return a BeanWrapper for the new instance
 */
public BeanWrapper instantiateUsingFactoryMethod(
		String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
	BeanWrapperImpl bw = new BeanWrapperImpl();
	String factoryBeanName = mbd.getFactoryBeanName();
    // 抽象工厂模式,获取工厂的工厂
    Object factoryBean = this.beanFactory.getBean(factoryBeanName);
	bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
		return bw;
}


/**
	 * Fill in any missing property values with references to
	 * other beans in this factory if autowire is set to "byName".
	 * @param beanName the name of the bean we're wiring up.
	 * Useful for debugging messages; not used functionally.
	 * @param mbd bean definition to update through autowiring
	 * @param bw the BeanWrapper from which we can obtain information about the bean
	 * @param pvs the PropertyValues to register wired objects with
	 */
	protected void autowireByName(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
    if (containsBean(propertyName)) {
        // 创建依赖
	    Object bean = getBean(propertyName);
        // 保存成 Bean的属性值
	    pvs.add(propertyName, bean);
        // 把 依赖关系存入Map
	    registerDependentBean(propertyName, beanName);
    }
}

// Bean间依赖 
// org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#registerDependentBean
/** Map between dependent bean names: bean name to Set of dependent bean names. */
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);

/** Map between depending bean names: bean name to Set of bean names for the bean's dependencies. */
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

/** Cache of singleton objects: bean name to bean instance. 已经创建的单例*/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Names of beans that are currently in creation. 正在创建的单例*/
private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

/**
 * Register a dependent bean for the given bean,
 * to be destroyed before the given bean is destroyed.
 * @param beanName the name of the bean
 * @param dependentBeanName the name of the dependent bean
 */
public void registerDependentBean(String beanName, String dependentBeanName) {
	String canonicalName = canonicalName(beanName);
	synchronized (this.dependentBeanMap) {
		Set<String> dependentBeans =
				this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
		if (!dependentBeans.add(dependentBeanName)) {
			return;
		}
	}
	synchronized (this.dependenciesForBeanMap) {
		Set<String> dependenciesForBean =
				this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
		dependenciesForBean.add(canonicalName);
	}
}



/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular referenc
 * @param beanName the name of the bean to look for
 * @param allowEarlyReference whether early references should be created or 
 * @return the registered singleton object, or {@code null} if none found
    
    单例模式:双重检查锁 获取 单例
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) 
	// Quick check for existing instance without full singleton lock
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null && allowEarlyReference) {
		synchronized (this.singletonObjects) {
            // Consistent creation of early reference within full singleton lock
            singletonObject = this.singletonObjects.get(beanName);
    }
    }
}

创建类,创建类只有两种方式:

1. new 

2. 反射

显然,Spring 通过反射创建类。

管理类间依赖:BeanA 依赖  BeanB

1. 创建 BeanB

2. BeanB 加入到 BeanA 属性值

3. 建立 Map<BeanA,BeanB>

Spring 使用Map 管理 Bean 和Bean间依赖。

类创建使用的设计模式:

1. 抽象工厂模式,输入 Bean工厂 名称,输出 工厂实例

2. 工厂方法模式,输入 Bean 名称,输出 Bean实例

3. 单例模式:双重检查锁,获取全局唯一实例

接口划分粒度

接口要定义的够 抽象、通用。

原则上,接口一旦定义好,就不能再做改动。-> 不改老代码

那如何基于老代码做扩展呢?下篇,类扩展。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值