主要介绍
单例设计模式,代理设计模式,观察者设计模式,模板模式(Template), 适配器模式,装饰模式(Decorator),命令模式(Command),策略模式(Strategy);(单代命 观模装适)。
1. 单例模式:
一般包括:懒汉式单例、饿汉式单例、登记式单例。
-
特点:
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。 -
用途:
在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。 -
示例:
//懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//静态工厂方法
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
return singleton;
}
}
//静态内部类时,不需要用同步
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
//饿汉式单例类.在类初始化时,已经自行实例化
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//静态工厂方法
public static Singleton1 getInstance() {
return single;
}
}
//登记式单例
/*实际上维护了一组单例类的实例,将这些实例存放在一个Map(登记薄)中,对于已经登记过的实例,则从Map直接返回,对于没有登记的,则先登记,然后返回。它用的比较少且麻烦,另外其实内部实现还是用的饿汉式单例,这里忽略。*/
2. 代理模式
是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
3. 命令模式
是指为了实现调用者角色与接收者角色之间,没有任何依赖关系,即完全解耦。
-
命令模式的4个角色:
Command:定义命令的统一接口
ConcreteCommand:Command接口的实现者,用来执行具体的命令,有时也直接用来充当Receiver。
Receiver:命令的实际执行者
Invoker:命令的请求者,是命令模式中最重要的角色。这个角色用来对各个命令进行控制。 -
示例:
//通用Receiver类
public abstract class Receiver {
public abstract void doSomething();
}
//具体Receiver类
public class ConcreteReciver1 extends Receiver{
//每个接收者都必须处理一定的业务逻辑
public void doSomething(){ }
}
public class ConcreteReciver2 extends Receiver{
//每个接收者都必须处理一定的业务逻辑
public void doSomething(){ }
}
//抽象Command类
public abstract class Command {
public abstract void execute();
}
//具体的Command类
public class ConcreteCommand1 extends Command {
//对哪个Receiver类进行命令处理
private Receiver receiver;
//构造函数传递接收者
public ConcreteCommand1(Receiver _receiver){
this.receiver = _receiver;
}
//必须实现一个命令
public void execute() {
//业务处理
this.receiver.doSomething();
}
}
public class ConcreteCommand2 extends Command {
//哪个Receiver类进行命令处理
private Receiver receiver;
//构造函数传递接收者
public ConcreteCommand2(Receiver _receiver){
this.receiver = _receiver;
}
//必须实现一个命令
public void execute() {
//业务处理
this.receiver.doSomething();
}
}
//调用者Invoker类
public class Invoker {
private Command command;
public void setCommand(Command _command){
this.command = _command;
}
public void action() {
this.command.execute();
}
}
//场景类
public class Client {
public static void main(String[] args){
Invoker invoker = new Invoker();
Receiver receiver = new ConcreteReceiver1();
Command command = new ConcreteCommand1(receiver);
invoker.setCommand(command);
invoker.action();
}
}
4. 观察者设计模式
是指在对象之间定义了一对多的依赖,这样一来,当一个对象改变状态,依赖它的对象会收到通知并自动更新。
-
其包含四个角色:
- 抽象被观察者角色:也就是一个抽象主题,它把所有对观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
- 抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
- 具体被观察者角色:也就是一个具体的主题,在集体主题的内部状态改变时,所有登记过的观察者发出通知。
- 具体观察者角色:实现抽象观察者角色所需要的更新接口,一边使本身的状态与制图的状态相协调
-
使用场景举例:
有一个微信公众号服务,不定时发布一些消息,关注公众号就可以收到推送消息,取消关注就收不到推送消息。 -
示例:
/***
* 抽象被观察者接口
* 声明了添加、删除、通知观察者方法
* @author jstao
*
*/
public interface Observerable {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
//定义一个抽象观察者接口
/***
* 抽象观察者
* 定义了一个update()方法,当被观察者调用notifyObservers()方法时,观察者的update()方法会被回调。
* @author jstao
*
*/
public interface Observer {
public void update(String message);
}
//定义被观察者,实现了Observerable接口,对Observerable接口的三个方法进行了具体实现,同时有一个List集合,用以保存注册的观察者,等需要通知观察者时,遍历该集合即可。
/**
* 被观察者,也就是微信公众号服务
* 实现了Observerable接口,对Observerable接口的三个方法进行了具体实现
* @author jstao
*
*/
public class WechatServer implements Observerable {
//注意到这个List集合的泛型参数为Observer接口,设计原则:面向接口编程而不是面向实现编程
private List<Observer> list;
private String message;
public WechatServer() {
list = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if(!list.isEmpty())
list.remove(o);
}
//遍历
@Override
public void notifyObserver() {
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
}
public void setInfomation(String s) {
this.message = s;
System.out.println("微信服务更新消息: " + s);
//消息更新,通知所有观察者
notifyObserver();
}
}
//定义具体观察者,微信公众号的具体观察者为用户User
/**
* 观察者
* 实现了update方法
* @author jstao
*
*/
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送消息: " + message);
}
}
5. 模板模式
定义一个操作中算法的骨架,而将一些步骤延迟到子类中。也就是说,要在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。
- 示例:
public abstract class DodishTemplate { //模板类
/**
* 具体的整个过程
*/
protected void dodish(){
this.preparation();
this.doing();
this.carriedDishes();
}
/**
* 备料
*/
public abstract void preparation();
/**
* 做菜
*/
public abstract void doing();
/**
* 上菜
*/
public abstract void carriedDishes ();
}
public class EggsWithTomato extends DodishTemplate{ //具体实现类
@Override
public void preparation() {
System.out.println("洗并切西红柿,打鸡蛋。");
}
@Override
public void doing() {
System.out.println("鸡蛋倒入锅里,然后倒入西红柿一起炒。");
}
@Override
public void carriedDishes() {
System.out.println("将炒好的西红寺鸡蛋装入碟子里,端给客人吃。");
}
}
//代码中调用:
DodishTemplate eggsWithTomato = new EggsWithTomato();
eggsWithTomato.dodish();
6. 装饰模式
也叫做包装模式,是结构型设计模式之一。目的是为了给一个类或对象增加行为。可以是继承的一种替代。
-
四个角色:
Component:抽象组件,可以是一个接口或抽象类,是被装饰的原始对象
ConcreteComponent:组件的具体实现类。是被装饰的具体对象。
Decorator:抽象的装饰者。职责是装饰被装饰的对象。内部一定有一个对被装饰者的引用。一般情况下也是一个抽象类,根据具体逻辑实现不同的子类。如果逻辑简单可以直接是实现类。
ConcreteDecoratorA,B:具体的装饰者。 -
示例:
//先抽象组件类:
public abstract class Component {
public abstract void operate();
}
组件的一个具体实现类,也就是被装饰者者:
public class ConcreteComponent extends Component {
@Override
public void operate() {
System.out.println("被装饰者的操作");
}
}
//抽象的装饰者,持有一个被装饰者的引用:
public abstract class Decorator extends Component {
private Component component;
public Decorator(Component component) { //采用传参方式,替代继承类的方式,这样区分开继承利于后期管理
this.component = component;
}
@Override
public void operate() {
component.operate();
}
}
//具体的两个装饰者,拓展功能:
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operate() {
operateA();
super.operate();
operateB();
}
private void operateA(){
System.out.println("装饰者A在被装饰者的操作之前加些操作");
}
private void operateB(){
System.out.println("装饰者A在被装饰者的操作之前后加些操作");
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operate() {
operateA();
super.operate();
operateB();
}
private void operateA(){
System.out.println("装饰者B在被装饰者的操作之前加些操作");
}
private void operateB(){
System.out.println("装饰者B在被装饰者的操作之前后加些操作");
}
}
//客户端调用:
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(component);
ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB(component);
concreteDecoratorA.operate();
concreteDecoratorB.operate();
}
}
7. 适配器模式
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作,可以理解成转换器。 例子:https://blog.csdn.net/lmb55/article/details/51008762
8. 策略模式
定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法"独立"于使用它的客户而独立变化。
-
使用场景:
1.针对同一类型问题的多种处理方式,仅仅是具体行为有差别时;
2.需要安全地封装多种同一类型的操作时;
3.出现同一抽象类有多个子类,而又需要使用 if-else 或者 switch-case 来选择具体子类时。 -
示例:
public interface CalPrice {
//根据原价返回一个最终的价格
Double calPrice(Double orgnicPrice);
}
public class Orgnic implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice;
}
}
public class Vip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.9;
}
}
public class SuperVip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.8;
}
}
public class GoldVip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.7;
}
}
public class Player {
private Double totalAmount = 0D;//客户在鹅厂消费的总额
private Double amount = 0D;//客户单次消费金额
private CalPrice calPrice = new Orgnic();//每个客户都有一个计算价格的策略,初始都是普通计算,即原价
//客户购买皮肤,就会增加它的总额
public void buy(Double amount) {
this.amount = amount;
totalAmount += amount;
if (totalAmount > 30000) {//30000则改为金牌会员计算方式
calPrice = new GoldVip();
} else if (totalAmount > 20000) {//类似
calPrice = new SuperVip();
} else if (totalAmount > 10000) {//类似
calPrice = new Vip();
}
}
//计算客户最终要付的钱
public Double calLastAmount() {
return calPrice.calPrice(amount);
}
}
//调用
Player player = new Player();
player.buy(5000D);
System.out.println("玩家需要付钱:" + player.calLastAmount());
网友评论