设计模式
单例模式【Singleton】
定义:确保全局最多只有一个对象
适用:构建缓慢的对象;需要统一管理的资源
优点:1.减少内存的占用
2.单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
3.因为类控制了实例化过程,所以类可以灵活更改实例化过程
缺点:1.很多全局状态 2. 线程安全性问题
创建:
1.双重锁模式【详解】
将同步内容下放到if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了
2.作为 Java 类的静态变量
3.使用框架提供的能力
变继承关系为组合关系
继承关系
1.描述 is-a 的关系
2.不要用继承关系来实现复用,要使用设计模式来实现复用
例 将Employee 变为 Manager
代码:state(状态)模式【详解】
Role.java
package interview.designpattern.company;
public interface Role {
void doWork();
}
Engineer.java
package interview.designpattern.company;
public class Engineer implements Role {
@Override
public void doWork() {
System.out.println("Doing engineer work.");
}
@Override
public String toString() {
return "Engineer";
}
}
Employee.java
package interview.designpattern.company;
import java.util.List;
import java.util.Objects;
public class Employee {
public static List<Employee> allEmployees;
private final String name;
private final int salary;
private Role role;
public Employee(String name, int salary, Role role) {
this.name = name;
this.salary = salary;
this.role = role;
}
public void doWork() { //新增代码
role.doWork();
}
public void getPaid(BankEndPoint bank) {
bank.payment(name, salary);
}
// Package private for logic in the package to control
// when employees are loaded.
static void loadAllEmployees() {
// Loads all employees from database.
}
@Override
public int hashCode() {
return Objects.hash(name, salary, role);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
Employee other = (Employee) obj; //新增代码
return Objects.equals(this.name, other.name)
&& Objects.equals(this.salary, other.salary)
&& Objects.equals(this.role, other.role);
}
@Override
public String toString() {
return "Employee [name=" + name
+ ", salary=" + salary
+ ", role=" + role + "]";
}
public String getName() {
return name;
}
public int getSalary() {
return salary;
}
public Role getRole() {//新增代码
return role;
}
public void setRole(Role role) {//新增代码
this.role = role;
}
}
Tester.java
package interview.designpattern.company;
import java.util.Arrays;
import java.util.LinkedList;
public class Tester {
public static void main(String[] args) {
Employee employee1 = new Employee("John", 10000,
new Engineer());
Employee employee2 = new Employee("Mary", 20000,
new Engineer());
LinkedList<Employee> employees = new LinkedList<>();
employees.add(employee1);
employees.add(employee2);
System.out.println("Print using for each");
for (Employee employee : employees) {
System.out.println(employee);
}
System.out.println("Testing managers");
employee2.setRole(new Manager(Arrays.asList(employee1)));
for (Employee employee : employees) {
System.out.println(employee);
}
System.out.println("Testing doWork");
System.out.println("Employee1");
employee1.doWork();
System.out.println("Employee2");
employee2.doWork();
}
}
输出:
Decorator模式【详解】
装饰(Decorator)模式又名包装(Wrapper)模式。装饰模式以对客户端透明 的方式扩展对象的功能,是继承关系的一个替代方案。
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式使用原来被装饰的类的一个子类的实例,把客户端的调用委派到被装饰类。关键在于这种扩展是完全透明的。与生成子类相比,它更具有灵活性。
LogginRunnable 和 CodingTask 都要满足 Runnable 接口
CodingTask 是真正做事的,LogginRunnable 是装饰
代码:LoggingRunnable.java
package interview.designpattern.task;
public class LoggingRunnable implements Runnable {
private final Runnable innerRunnable;
public LoggingRunnable(Runnable innerRunnable) {
this.innerRunnable = innerRunnable;
}
@Override
public void run() {
long startTime = System.currentTimeMillis();
System.out.println("Task started at "
+ startTime);
innerRunnable.run();
System.out.println("Task finished. Elapsed time: "
+ (System.currentTimeMillis() - startTime));
}
}
CodingTask.java
package interview.designpattern.task;
public class CodingTask implements Runnable {
private final int employeeId;
public CodingTask(int employeeId) {
this.employeeId = employeeId;
}
@Override
public void run() {
System.out.println("Employee " + employeeId
+ " started writing code.");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("Employee " + employeeId
+ " finished writing code.");
}
}
TransactionalRunnable.java
package interview.designpattern.task;
public class TransactionalRunnable implements Runnable {
private final Runnable innerRunnable;
public TransactionalRunnable(Runnable innerRunnable) {
this.innerRunnable = innerRunnable;
}
@Override
public void run() {
boolean shouldRollback = false;
try {
beginTransaction();
innerRunnable.run();
} catch (Exception e) {
shouldRollback = true;
throw e;
} finally {
if (shouldRollback) {
rollback();
} else {
commit();
}
}
}
private void commit() {
System.out.println("commit");
}
private void rollback() {
System.out.println("rollback");
}
private void beginTransaction() {
System.out.println("beginTransaction");
}
}
Tester.java
package interview.designpattern.task;
public class Tester {
public static void main(String[] args) {
new LoggingRunnable(
new TransactionalRunnable(
new CodingTask(0))).run();
}
}
输出:
如何创建对象
使用 new 来创建的缺点:
1.编译时必须决定创建那个类的对象
2.参数意义不明确
解决方法:
抽象工厂(Abstract Factory)模式【详解】
抽象工厂模式(Abstract Factory Pattern)是一种比较常用的模式,其定义如下:
Provide an interface for creating families of related or dependent objects without specifying their concrete classes. 即为创建一组相关或相互依赖的对象提供一个接口,而且无须指定它们的具体类。它的通用类图如下:
1)封装性。每个产品的实现类不是高层模块要关心的,它要关心的是接口,是抽象,它不关心对象是如何创建出来的,这都由工厂类负责的,只要知道工厂类是谁,我就能创建一个需要的对象,省时省力。
2)产品族内的约束为非公开状态。例如生产男女比例的问题上,猜想女娲娘娘肯定有自己的打算,那么在抽象工厂模式中,这些约束都在工厂内里面实现的。
抽象工厂模式最大的缺点就是产品族扩展非常困难。如果我们要增加一个产品C,也就是说产品族由原来的A和B增加到3个,那么我们首先要在抽象类AbstractCreator中增加createProductC()方法,然后两个实现类都要修改……说到这里,已经知道了扩展的弊端了……
注意这里是产品族扩展比较困难,而不是产品等级扩展困难。产品等级扩展还是非常容易的,增加一个产品等级,只要增加一个工厂类负责新增加出来的产品生产任务即可。也就是说横向扩展容易,纵向扩展难。