23种设计模式(Java)
所有内容来源于网络。
uml使用的关系符号参考 http://www.uml.org.cn/oobject/201510214.asp 。
代码见 https://gitee.com/wuyicode/design-pattern 。
设计模式主要分三个类型
-
创建型
-
结构型
-
首先谈谈策略模式
属于 行为类模式 ,把行为抽象成接口,再聚合到类里。
UML中的聚合与组合
UML的类图中一般包含五种关系即 关联 聚合 组合 泛化 依赖。
参考 https://blog.csdn.net/liushuijinger/article/details/6994265 。
简单地说, 组合是不可分割的,聚合就不是。聚合关系比组合关系的紧密型要差些。
聚合的关系明显没有组合紧密 。
大雁不会因为雁群解散而无法生存,而翅膀就无法脱离大雁而单独生存,所以组合关系的类具有相同的生命周期 。
雁群
class GooseGroup
{
public Goose goose;
public GooseGroup(Goose goose){
this.goose = goose;
}
}
大雁
public class Goose
{
public Wings wings;
public Goose(){
wings=new Wings();
}
}
interface IStrategy {
public void doSomething();
}
class ConcreteStrategy1 implements IStrategy {
public void doSomething() {
System.out.println("具体策略1");
}
}
class ConcreteStrategy2 implements IStrategy {
public void doSomething() {
System.out.println("具体策略2");
}
}
class Context {
private IStrategy strategy;
public Context(IStrategy strategy){
this.strategy = strategy;
}
public void execute(){
strategy.doSomething();
}
}
public class Client {
public static void main(String[] args){
Context context;
System.out.println("-----执行策略1-----");
context = new Context(new ConcreteStrategy1());
context.execute();
System.out.println("-----执行策略2-----");
context = new Context(new ConcreteStrategy2());
context.execute();
}
}
一个对象要时刻监听着另一个对象,只要它的状态一发生改变,自己随之要做出相应的行动。
public interface Subject {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
@Data
public class WeatherData implements Subject {
private float temperatrue;
private float pressure;
private float humidity;
private ArrayList<Observer> observers;
public WeatherData() {
observers = new ArrayList<>();
}
//当数据有更新时,就调用 setData
public void setData(float temperature, float pressure, float humidity) {
this.temperatrue = temperature;
this.pressure = pressure;
this.humidity = humidity;
notifyObservers();
}
@Override
public void registerObserver(Observer o) {
observers.clear();
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
if(observers.contains(o))
observers.remove(o);
}
@Override
public void notifyObservers() {
observers.forEach( observer -> observer.update(temperatrue, pressure, humidity));
}
}
调用示例。WeatherData 是被观察的对象。
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
weatherData.registerObserver(new CurrentConditions());
weatherData.setData(10f, 40f, 50.55f);
System.out.println("----------------------------");
weatherData.registerObserver(new BaiduSite());
weatherData.setData(20f, 40f, 50.55f);
}
// 实际的观察者
public class CurrentConditions implements Observer {
// 温度,气压,湿度
private float temperature;
private float pressure;
private float humidity;
@Override
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("***Today mTemperature: " + temperature + "***");
System.out.println("***Today mPressure: " + pressure + "***");
System.out.println("***Today mHumidity: " + humidity + "***");
}
}
public class BaiduSite implements Observer {
private float temperature;
private float pressure;
private float humidity;
@Override
public void update(float temperature, float pressure, float humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("===百度网站====");
System.out.println("***百度网站 气温 : " + temperature + "***");
System.out.println("***百度网站 气压: " + pressure + "***");
System.out.println("***百度网站 湿度: " + humidity + "***");
}
}
@Data
public abstract class Drink {
public String des; // 描述
private float price = 0.0f;
public abstract float cost(); // 计算费用的抽象方法
}
public class Decorator extends Drink {
Drink obj;
public Decorator(Drink drink) {
obj = drink;
}
@Override
public float cost() {
return super.getPrice() + obj.getPrice();
}
@Override
public String getDes() {
return des + " " + getPrice() + " && " + obj.getDes();
}
}
public class Coffee extends Drink {
@Override
public float cost() {
return 1;
}
}
public class Chocolate extends Decorator {
public Chocolate(Drink drink) {
super(drink);
setDes("巧克力");
setPrice(3.1f);
}
}
public class Milk extends Decorator {
public Milk(Drink obj) {
super(obj);
setDes("牛奶");
setPrice(2.0f);
}
}
调用示例
public static void main(String[] args) {
Drink order = new Coffee();
order = new Milk(order);
order = new Chocolate(order);
System.out.println("order 加入一份牛奶 加入一份巧克力 费用 =" + order.cost());
System.out.println("order 加入一份牛奶 加入一份巧克力 描述 = " + order.getDes());
}
特点是
-
禁止通过new 来 创建对象
-
构造函数 是 private
-
给出 getInstance() 函数,来提供单例对象。
确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
最简单的 饿汉式单例
/**
* 静态常量方法
* 缺点是没有懒加载,有可能造成浪费。
* 优点是,线程安全。
*/
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
public class Singleton {
private static Singleton singleton;
private Singleton(){}
// 加入同步处理的代码,解决线程安全问题。
public static synchronized Singleton getInstance(){
if(singleton==null){
singleton = new Singleton();
}
return singleton;
}
}
在
class Singleton06 {
// 构造函数私有化
private Singleton06() {
}
// volatile保证线程的可见性, 效果更好。
private static volatile Singleton06 instance;
// 双重检查
public static Singleton06 getInstance() {
if (instance == null) {
synchronized (Singleton06.class) {
if (instance == null)
instance = new Singleton06();
}
}
return instance;
}
}
class Singleton07 {
// 构造函数私有化
private Singleton07() {
}
/**
* 静态内部类 实现了懒加载和线程安全。
*/
private static class SingletonInstance {
private static final Singleton07 INSTANCE = new Singleton07();
}
public static synchronized Singleton07 getInstance(){
return SingletonInstance.INSTANCE;
}
}
enum Singleton08{
INSTANCE,
;
public void sayOK() {
System.out.println("ok~");
}
}
简单工厂
简单工厂 不是 23种设计模式。这个方法不好,违反了 开闭原则。所以不提倡。
public class SimpleFactory {
public static Pizza createPizza(String orderType) {
Pizza pizza = null;
System.out.println("使用简单工厂模式2");
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName(" 希腊披萨 ");
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName(" 奶酪披萨 ");
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName("胡椒披萨");
}
return pizza;
}
}
/**
* 抽象类
*/
public abstract class Pizza {
protected String name;
/**
* 抽象方法
* 各个子类的不同之处就在这里
*/
public abstract void prepare();
public void bake(){}
public void cut(){}
public void box(){}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
目的是 便于日后扩展其它类。这里给出的 Pizza() 类,规定了 方法,它的基类去实现这些方法即可。
抽象工厂
抽象工厂是在 工厂方法的基础上,再做一层抽象。可以理解为 工厂的工厂。
命令模式
命令模式的适用场景
-
Command类:是一个抽象类,类中对需要执行的命令进行声明,一般来说要对外公布一个execute方法用来执行命令。
-
ConcreteCommand类:Command类的实现类,对抽象类中声明的方法进行实现。
-
Client类:最终的客户端调用类。
以上三个类的作用应该是比较好理解的,下面我们重点说一下Invoker类和Recevier类。
-
Invoker类:调用者,负责调用命令。
-
Receiver类:接收者,负责接收命令并且执行命令。
class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void action(){
this.command.execute();
}
}
abstract class Command {
public abstract void execute();
}
class ConcreteCommand extends Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver){
this.receiver = receiver;
}
public void execute() {
this.receiver.doSomething();
}
}
class Receiver {
public void doSomething(){
System.out.println("接受者-业务逻辑处理");
}
}
public class Client {
public static void main(String[] args){
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
//客户端直接执行具体命令方式(此方式与类图相符)
command.execute();
//客户端通过调用者来执行命令
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.action();
}
}
代理模式
静态代理,是把目标对象,通过接口来聚合 。
/**
* 静态代理
*/
public class TeacherDaoProxy implements ITeacherDao {
private ITeacherDao target; // 目标对象,通过接口来聚合
public TeacherDaoProxy(ITeacherDao target) {
this.target = target;
}
@Override
public void teach() {
target.teach();
}
}
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println(" 老师授课中 。。。。。");
}
}
public static void main(String[] args) {
TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(new TeacherDao());
teacherDaoProxy.teach();
}
动态代理
动态代理的代理类 是动态生成的。
可以分为
-
基于接口的jdk动态代理
-
基于类的 cglib实现
主要内容有 :Proxy 和 InvocationHandler。
先说 jdk动态代理,本质是,使用反射机制。
/**
* 动态代理
*/
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance(){
ClassLoader loader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
Object proxyInstance = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理开始~~");
// 反射机制调用目标对象的方法
Object invoke = method.invoke(target, args);
return invoke;
}
});
return proxyInstance;
}
}
public class TeacherDao implements ITeacherDao {
@Override
public void teach() {
System.out.println(" 老师授课中.... ");
}
@Override
public void sayHello(String name) {
System.out.println("hello " + name);
}
}
public static void main(String[] args) {
ITeacherDao instance = (ITeacherDao) new ProxyFactory(new TeacherDao()).getProxyInstance();
// 两次调用方法, 也就意味着两次使用了invoke 反射。
instance.teach();
instance.sayHello("tom");
}
cglib实现方式,是增强的动态代理, 不需要实现接口。
添加maven依赖。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
public class ProxyFactory implements MethodInterceptor {
//维护一个目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 返回一个代理对象: 是 target 对象的代理对象
public Object getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib代理模式 ~~ 开始");
Object invoke = method.invoke(target, objects);
System.out.println("Cglib代理模式 ~~ 提交");
return invoke;
}
}
public class TeacherDao {
public String teach() {
System.out.println(" 老师授课中 , 我是cglib代理,不需要实现接口 ");
return "hello";
}
}
public static void main(String[] args) {
TeacherDao instance = (TeacherDao) new ProxyFactory(new TeacherDao()).getProxyInstance();
String res = instance.teach();
System.out.println(res);
}