简单总结一下大佬文章方方便记忆!
转载博客:
23种设计模式学习导航(Java完整版)
Java设计模式之一:观察者模式
目录
1. 设计模式分类
1.1. 行为型模式
1.1.1. 策略模式
策略模式:它将对象和行为分开,将行为定义为 一个行为接口 和 具体行为的实现。策略模式最大的特点是行为的变化,行为之间可以相互替换。本模式使得算法可独立于使用它的用户而变化。
- 策略模式包含如下角色:
- Strategy: 抽象策略类:策略是一个接口,该接口定义若干个算法标识,即定义了若干个抽象方法
- ConcreteStrategy: 具体策略类:具体策略实现 Strategy 所定义的抽象方法,即给出算法标识的具体方法。通过 ConcreteStrategy 对象使得具体行为实现 与 调用行为解耦。
- Context: 环境类 /上下文类):上下文是依赖于 Strategy:,即上下文包含用 Strategy: 声明的变量。上下文提供一个方法,持有一个 ConcreteStrategy 的引用,最终给客户端调用。该方法委托 策略变量 调用 ConcreteStrategy 所实现的策略接口中的方法来完成具体功能!
-
应用场景
假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定比这要复杂。比如,本网站可能对所有的高级会员提供每本20%的促销折扣:对中级会员提供每本10%的促销折扣;对初级会员没有折扣。- 根据描述,折扣是根据以下的几个算法中的一个进行的:
- 算法一:对初级会员没有折扣。
- 算法二:对中级会员提供10%的促销折扣。
- 算法三:对高级会员提供20%的促销折扣。
给出一本图书,如300元,若是高级会员,则输出价格为240元。
-
场景实现
- (1) 抽象类策略(Strategy)
public interface MemberStrategy {
// 一个计算价格的抽象方法
//price商品的价格 n商品的个数
public double calcPrice(double price, int n);
}
- (2) 具体实现类(Concrete Strategy)
// 普通会员——不打折
public class PrimaryMemberStrategy implements MemberStrategy { // 实现策略
//重写策略方法具体实现功能
@Override
public double calcPrice(double price, int n) {
return price * n;
}
}
// 普通会员——不打折
// 中级会员 打百分之10的折扣
public class IntermediateMemberStrategy implements MemberStrategy{
@Override
public double calcPrice(double price, int n) {
double money = (price * n) - price * n * 0.1;
return money;
}
}
// 普通会员——不打折
// 高级会员类 20%折扣
public class AdvanceMemberStrategy implements MemberStrategy{
@Override
public double calcPrice(double price, int n) {
double money = price * n - price * n * 0.2;
return money;
}
}
- (3) 上下文累(Context )
/**
* 负责和具体的策略类交互
* 这样的话,具体的算法和直接的客户端调用分离了,使得算法可以独立于客户端独立的变化。
*/
// 上下文类/环境类
public class MemberContext {
// 用户折扣策略接口
private MemberStrategy memberStrategy;
// 注入构造方法
public MemberContext(MemberStrategy memberStrategy) {
this.memberStrategy = memberStrategy;
}
// 计算价格
public double qoutePrice(double goodsPrice, int n){
// 通过接口变量调用对应的具体策略
return memberStrategy.calcPrice(goodsPrice, n);
}
}
1.1.2. 命令模式
命令模式(Command Pattern)是一种行为型设计模式,又叫动作模式或事务模式。它将请求(命令)封装成对象,使得可以用不同的请求对客户端进行参数化,具体的请求可以在运行时更改、排队或记录,它讲发出者和接收者解耦 (顺序:发出者–>命令–>接收者)
本质:封装请求
-
应用场景
餐厅点餐:在一家餐厅中,服务员充当调用者,厨师充当接收者,菜品可以作为具体命令。当顾客想点菜时,服务员会将顾客的需求封装成一个命令对象,并传递给厨师。厨师根据命令对象中的信息来完成相应的烹饪工作。这样,顾客和厨师之间不需要直接沟通,而是通过命令对象来实现点餐和烹饪的解耦。 -
点餐场景实现
- (1) 抽象命令(Command)- Command
public interface Command {
//点菜
void order();
//取消点菜
void cancelOrder();
}
- (2) 接收者(Receiver)- Chef
public class Chef {
public void cook() {
System.out.println("厨师执行点菜命令:正在烹饪菜品...");
}
public void cancelCooking() {
System.out.println("厨师执行取消命令:停止烹饪菜品!");
}
}
- (3) 具体命令(Concrete Command)- OrderCommand
public class OrderCommand implements Command{
// 厨师
private Chef chef;
public OrderCommand(Chef chef) {
this.chef = chef;
}
public void order() {
//与具体的烹饪者(厨师)关联,执行点菜操作
chef.cook();
}
public void cancelOrder() {
//与具体的烹饪者(厨师)关联,执行取消点菜操作
chef.cancelCooking();
}
}
- (4) 调用者(invoker)- Waitor
public class Waiter {
//命令对象
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void takeOrder() {
// 服务员接收到顾客的点菜请求
System.out.println("服务员接收到顾客(客户端)点菜请求!");
// 执行点菜操作
command.order();
}
public void cancelOrder() {
// 服务员收到顾客的取消点菜请求
System.out.println("服务员接收到顾客(客户端)取消点菜请求!");
// 执行取消点菜操作
command.cancelOrder();
}
}
1.1.3. 模板模式
- 模板模式特征
- 基于继承关系实现!
- 将定义的算法抽象成一组步骤,在抽象类中定义算法框架,具体的操作留给子类来实现!
- 角色构成
- 抽象类(Abstract):包含一个或多个抽象方法,这些方法有子类来具体实现。Abstract****中通常包含一个模板方法,用来调用抽象方法与具体方法,控制算法执行顺序,还可以定义钩子方法,用于在算法中进行条件控制!
- 具体类(ConcreteClass):继承抽象类,实现抽象方法!
-
应用场景
假设订外卖的过程包含三个步骤:选择外卖、支付、取外卖、是否打赏,我们可以定义一个OderFood的抽象类,那么选择外卖就可以是抽象方法,需要子类取实现它,支付和取外卖可以定义为具体方法,另外是否打赏为钩子方法,子类可以决定是否对算法的不同进行挂钩,还需要定义一个模板方法,用以控制流程;不同的商家,如KFC、星巴克就是具体类。 -
订外卖场景实现
- (1) 抽象命令(Command)- Command
/**
* @author Created by njy on 2023/6/24
* 1.抽象类(Abstract Class):点外卖
* 包含选择外卖、支付、取外卖三个方法,
* 其中选择外卖为抽象方法,需要子类实现
* 支付、取外卖为具体方法
* 另外是否打赏为钩子方法,子类可以决定是否对算法的不同进行挂钩
*/
public abstract class OrderFood {
//模板方法
public void order(){
selectFood();
pay();
getFood();
}
//选择外卖 抽象方法 由子类实现具体细节
public abstract void selectFood();
//是否打赏 钩子方法 可以重写来做条件控制
public boolean isGiveAward(){
return false;
}
//-------具体方法----------
public void pay(){
System.out.println("支付成功,外卖小哥正在快马加鞭~~");
}
//取外卖
public void getFood(){
System.out.println("取到外卖");
if (isGiveAward()){
System.out.println("打赏外卖小哥");
}
}
}
- (2) 具体类(Concrete Class)
/**
* @author Created by njy on 2023/6/24
* 具体类(Concrete Class):星巴克
*/
public class Starbucks extends OrderFood{
//实现父类方法
@Override
public void selectFood() {
System.out.println("一杯抹茶拿铁");
}
//重写钩子方法,打赏外卖小哥
@Override
public boolean isGiveAward(){
return true;
}
}
/**
* @author Created by njy on 2023/6/24
* 具体类(Concrete Class):KFC
*/
public class KFC extends OrderFood{
@Override
public void selectFood() {
System.out.println("一份汉堡炸鸡四件套");
}
}
- (3) 测试
/**
* @author Created by njy on 2023/6/24
* 模板模式测试类
*/
@SpringBootTest
public class TestTemplate {
@Test
void testTemplate(){
//星巴克(重写了钩子方法,打赏外卖小哥)
OrderFood orderFood=new Starbucks();
orderFood.order();
System.out.println("--------KFC------------");
//KFC
OrderFood orderFood1=new KFC();
orderFood1.order();
}
}
1.1.4. 观察者模式
- 观察者模式特征
- 由观察者与被观察者组成!
- 当被观察者状态发生改变时,它会通知所有的观察者对象,使他们能够及时做出响应!
- 角色构成
- 主题(Subject):定义了 Concrete Subject需要实现的方法,如注册、注销和通知观察者(Concrete Observer)。
- 观察者(Observer)定义了 Concrete Observer需要实现的方法,如根据Concrete Subject更新自己状态的方法。
- 具体主题(Concrete Subject):实现主题类(Subject),具体主题维护自身状态,并在状态变化时通知观察者。
- 具体观察者(Concrete Observer),它负责接收主题的通知并执行相应的操作。
-
应用场景
我们创建了一个具体主题对象 subject 和两个具体观察者对象 observer1 和 observer2。当主题的状态发生变化时,它会通知所有注册的观察者,并调用其 update() 方法进行更新。 -
场景实现
import java.util.ArrayList;
import java.util.List;
// 主题接口
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 具体主题类
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyObservers();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
// 观察者接口
interface Observer {
void update();
}
// 具体观察者类
class ConcreteObserver implements Observer {
private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject subject) {
this.subject = subject;
subject.registerObserver(this);
}
@Override
public void update() {
System.out.println("State updated: " + subject.getState());
}
}
// 测试
public class ObserverPatternExample {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver(subject);
ConcreteObserver observer2 = new ConcreteObserver(subject);
// 修改主题状态,观察者将会得到通知并更新
subject.setState(5);
}
}
1.1.5. 迭代器模式
提供了一种统一的方式来访问集合对象中的元素,而不是暴露集合内部的表示方式。
- 角色构成
- 抽象迭代器(Iterator):定义遍历 ConcreteAggregate 所需抽象方法,如hashNext(),next()方法等。
- 具体迭代器(Concrete Iterator)实现 Iterator中的方法,提供遍历ConcreteAggregate的具体逻辑。
- 抽象聚合器(Aggregate):定义操作 Concrete Iterator 的方法,如获取迭代器Concrete Iterator,向 Concrete Iterator 中添加集合中的对象,删除集合中的对象。
- 具体聚合器(ConcreteAggregate),Aggregate 的实现类!
- 应用场景
下面以班级名单为例,解释一下迭代器模式。
- 抽象迭代器:StudentIterator
- 具体迭代器:StudentListIterator
- 抽象聚合器:StudentAggregate
- 具体聚合器:ClassList
- 场景实现
public class Student {
public int age;
public String name;
public Student(int age, String name){
this.age = age;
this.name = name;
}
}
public abstract class StudentIterator extends java.utils.Iterable {}
public class StudentListIterator implements StudentIterator {
public int index = 0;
public List<Student> list = new ArrayList<Student>();
public StudentListIterator(List<Student> list){
this.list = list;
this.index = 0;
}
public boolean hasNext(){
return index > this.list.size();
};
public Student next(){
Student stu = this.list.get(this.index)
this.index++;
return stu;
};
}
public abstract class StudentAggregate {
public abstract Iterable getIterable();
public abstract void add();
}
public class ClassList implements StudentAggregate {
public List<Student> list = null;
public ClassList(List<Student> list){
this.list = list;
}
public Iterable getIterable(){
return new StudentIterator(this.list);
};
public void add(Student stu){
this.list.add(stu)
};
}
1.2. 构建型模式
1.2.1. 单例模式
- 单例模式:要求一个类仅有一个实例!
- .生活场景
- 一个班级只有一个班主任!
- 代码实现
public class Singleton {
private Singleton() {}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
private static Singleton instance1=null;
static {
instance1=new Singleton();
}
public Singleton getInstance1(){
return instance1;
}
}
1.2.2. 工厂模式 (Factory)
工厂模式:工厂模式属于创建型设计模式,它用于解耦对象的创建和使用。通常情况下,我们创建对象时需要使用new操作符,但是使用new操作符创建对象会使代码具有耦合性。工厂模式通过提供一个公共的接口,使得我们可以在不暴露对象创建逻辑的情况下创建对象。
- 工厂模式分为三种类型:
- 简单工厂
- 方法工厂
- 抽象工厂
本质: 对获取对象过程的抽象。\
- 工厂模式包含如下角色:
-
Product(抽象产品角色):
- Product是简单工厂模式所创建的所有ConcreteProduct 的父类,负责描述所有ConcreteProduct 所共有的公共接口.
- Product的引入将提高系统的灵活性,使得 Factory 中只需定义一个工厂方法,因为所有创建的ConcreteProduct 都是其子类对象。
-
ConcreteProduct(具体产品类) ConcreteProduct 是简单工厂模式的创建目标,所有创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的抽象方法 。
-
Factory(工厂角色):
- 它是简单工厂模式的核心,负责实现创建所有 ConcreteProduct 的内部逻辑;
- 工厂类可以直接被外界直接调用,创建所需的 ConcreteProduct ;
- 在Factory中提供了静态的工厂方法 factoryMethod(),它返回一个抽象产品类 Product,所有的 ConcreteProduct都是Product的子类。
-
应用场景
假设现在要设计一个贩卖各类书籍的电子商务网站的购物车系统。一个最简单的情况就是把所有货品的单价乘上数量,但是实际情况肯定比这要复杂。比如,本网站可能对所有的高级会员提供每本20%的促销折扣:对中级会员提供每本10%的促销折扣;对初级会员没有折扣。- 根据描述,折扣是根据以下的几个算法中的一个进行的:
- 算法一:对初级会员没有折扣。
- 算法二:对中级会员提供10%的促销折扣。
- 算法三:对高级会员提供20%的促销折扣。
给出一本图书,如300元,若是高级会员,则输出价格为240元。
-
场景实现
- (1) 抽象产品类(Strategy)
/**
* @author Evan Walker
* @version 1.0
* @desc 昂焱数据: https://www.ayshuju.com
* @date 2023/04/04 13:41:41
*/
public interface Fruit {
String getColor();
}`
- (2) 实际产品类(Concrete Strategy)
/**
* @author Evan Walker
* @version 1.0
* @desc 昂焱数据: https://www.ayshuju.com
* @date 2023/04/04 13:41:41
*/
public class Apple implements Fruit{
@Override
public String getColor() {
return "红色";
}
}
public class Orange implements Fruit{
@Override
public String getColor() {
return "橙色";
}
}
public class Pear implements Fruit{
@Override
public String getColor() {
return "黄色";
}
}
- (3) 工厂角色( Factory )
/**
* @author Evan Walker
* @version 1.0
* @desc 昂焱数据: https://www.ayshuju.com
* @date 2023/04/04 13:44:44
*/
public class FruitFactory {
public Fruit createFruit(String fruitType) {
if(fruitType.equalsIgnoreCase("Apple")){
return new Apple();
} else if(fruitType.equalsIgnoreCase("Orange")) {
return new Orange();
}else if(fruitType.equalsIgnoreCase("Pear")){
return new Pear();
}
return null;
}
}
1.2.3. 建造者模式
建造者模式:封装一个复杂对象的构建过程,并允许按步骤构建。
- 建造着模式包含如下角色:
- 产品类(Productiom):表示被构建的复杂对象,通常包含多个组成部分,由 ConcreteBuilder 逐步构建完成。
- 抽象构建者(Builder):定义了构建 Productiom 所需要的各个部分的构建方法。
- 具体构建者(ConcreteBuilder):实现 Builder 各个接口,并提供各个 Productiom 各个部分的构建方法。
- 指挥者类(Director):负责控制 Builder 的构建顺序,指挥 Builder 如何构建 Productiom 。
-
应用场景
肯德基套餐的实现:假设套餐主要由汉堡、薯条和饮料三种组成,每个组件都有不同种类和大小,并且每个套餐的组合方式也不同。下面以肯德徳套餐为例,解释建造者模式。- 产品类:Meal
- 抽象构建者:MealBuilder
- 具体构建者:BeefBurgerMealBuilder, ChickenMealBuilder、ShrimpMealBuilder
- 指挥者类:MealDirector
- 场景实现
- (1)象产品类: Meal
public class Meal {
//汉堡包
private String burger;
//薯条
private String fries;
//饮料
private String drink;
}
- (2) 抽象构建者(MealBuilder)
public abstract class MealBuilder {
protected Meal meal=new Meal();
//构建汉堡
public abstract void buildBurger();
//构建薯条
public abstract void buildFries();
//构建饮料
public abstract void buildDrink();
public Meal getMeal(){
return meal;
}
}
- (3) 具体构建者( BeefBurgerMealBuilder, ChickenMealBuilder、ShrimpMealBuilder)
public class ChickenMealBuilder extends MealBuilder{
@Override
public void buildBurger() {
meal.setBurger("鸡肉汉堡");
}
@Override
public void buildFries() {
meal.setFries("中份薯条");
}
@Override
public void buildDrink() {
meal.setDrink("大杯果汁");
}
}
public class BeefBurgerMealBuilder extends MealBuilder {
@Override
public void buildBurger() {
meal.setBurger("牛肉汉堡");
}
@Override
public void buildFries() {
meal.setFries("大份薯条");
}
@Override
public void buildDrink() {
meal.setDrink("中杯可乐");
}
}
public class ShrimpMealBuilder extends MealBuilder {
@Override
public void buildBurger() {
meal.setBurger("虾肉汉堡");
}
@Override
public void buildFries() {
meal.setFries("小份薯条");
}
@Override
public void buildDrink() {
meal.setDrink("大杯芬达");
}
}
- (4) 指导者(Director)
public class MealDirector {
private MealBuilder mealBuilder;
public void setMealBuilder(MealBuilder mealBuilder){
this.mealBuilder=mealBuilder;
}
public Meal getMeal(){
return mealBuilder.getMeal();
}
//制作套餐
public void constructMeal(){
mealBuilder.buildBurger();
mealBuilder.buildFries();
mealBuilder.buildDrink();
}
}
`
(5) 测试类
```java
public class TestBuilder {
@Test
void testBuilder(){
//创建指导者
MealDirector director=new MealDirector();
//执导建造牛肉套餐
director.setMealBuilder(new BeefBurgerMealBuilder());
director.constructMeal();
Meal meal = director.getMeal();
System.out.println("牛肉套餐:"+meal.toString());
//鸡肉套餐
director.setMealBuilder(new ChickenMealBuilder());
director.constructMeal();
Meal meal2 = director.getMeal();
System.out.println("鸡肉套餐:"+meal2.toString());
//虾肉套餐
director.setMealBuilder(new ShrimpMealBuilder());
director.constructMeal();
Meal meal3 = director.getMeal();
System.out.println("虾肉套餐:"+meal3.toString());
}
}
1.2.4. 原型模式
通过复制现有的实例来创建新的实例,无需知道相应类的信息。
- 角色组成
- 抽象原型类:定义一个抽象的克隆方法!
- 具体原型类:实现 抽象原型类(接口)定义的克隆方法,提供一个具体的克隆方法来复制自己!
- 客户端:使用原型类的对象来实现具体的操作,即通过原型对象来创建新得对象!
- 生活场景
- 下面以英雄联盟塞拉斯窃取其他英雄大招为例。
- 代码实现
-
(1)抽象原型类: HeroSkill
public class HeroSkill implements Cloneable{ private String name; private String bigMove; public HeroSkill(){ } public HeroSkill(String name, String bigMove){ this.name=name; this.bigMove=bigMove; } @Override public HeroSkill clone() { HeroSkill clone= null; try { clone = (HeroSkill) super.clone(); } catch (CloneNotSupportedException e) { throw new RuntimeException(e); } System.out.println("塞拉斯窃取"+name+"的大招:"+bigMove); return clone; } //英雄的大招展示 public void showSkill() { System.out.println(name+"的大招:"+bigMove); } }
-
(2)具体原型类: StealManFactory
public class StealManFactory { private HeroSkill heroSkill; public StealManFactory(HeroSkill heroSkill){ this.heroSkill=heroSkill; } public void setHeroSkill(HeroSkill heroSkill){ this.heroSkill=heroSkill; } public HeroSkill cloneHeroSkill(){ return heroSkill.clone(); } }
-
(3)客户端: TestPrototype
public class TestPrototype { @Test void testPrototype(){ //初始化英雄 HeroSkill heroSkill=new HeroSkill("盲僧","神龙摆尾"); //初始化工厂类(塞拉斯) StealManFactory factory=new StealManFactory(heroSkill); //复制英雄技能 HeroSkill cloneHeroSkill = factory.cloneHeroSkill(); //塞拉斯复制的技能 cloneHeroSkill.showSkill(); System.out.println("-------下方原英雄技能展示----------"); //原英雄技能 heroSkill.showSkill(); } }
-
1.3 结构型模式
1.3.1. 适配器模式
在不改变现有代码的情况下,使不兼容的接口之间能够正常工作,通过创建一个中间转换的适配器来将一个对象转换成我们所需要的接口。
- 角色组成
- 目标接口(target) :要是配的标准接口
- 源对象(source):要适配的不兼容对象
- 适配器对象(adapter)::充当其中的传唤对象,该对象将源对象转换成为标准接口
- 应用场景
当我们去国外旅游时,我们可能只会汉语,而当地人只会英语,那么这个时候就需要一个翻译员(翻译软件)来帮助我们。这就类似于适配器模式,通过一个适配器将一个不兼容的接口转成另外一个接口。下面以翻译为例,介绍一下类、接口、对象适配器。 - 场景实现
public interface Target {
void translate(String source,String target,String words);
}
public class Translator {
public void translateInZh(String words){
if("hello world!".equals(words)){
System.out.println("翻译成中文:”你好世界!“");
}
}
public void translateInEn(String words){
if("你好世界!".equals(words)){
System.out.println("Translate in English:”hello world!“");
}
}
}
public class ClassAdapter extends Translator implements Target {
@Override
public void translate(String source, String target, String words) {
if("中文".equals(source) && "英文".equals(target)) {
this.translateInEn(words);
} else {
this.translateInZh(words);
}
}
}
public class TestAdapter {
//类适配器
@Test
void classAdapter(){
//创建一个类适配器对象
ClassAdapter adapter=new ClassAdapter();
adapter.translate("中文", "英文", "你好世界!");
adapter.translate("英语","中文","hello world!");
}
}
1.3.2. 装饰着模式
允许动态地向对象添加新的行为而不影响原有行为!实现更佳灵活的代码复用与扩展!
- 角色组成
- 抽象构建(Component):一个接口/抽象类,规定了被装饰者的行为!
- 具体组件(Concrete Component):实现/继承Component,也即被装饰着!
- 抽象装饰着(decorator): 通用的 Concrete Component 装饰器,内部必须有一个引用指向Component,这个属性通常不是一个具体的实现,而是总的抽象组件接口,为了让其子类传入具体的实现类,这个类不是必须的,如果装饰逻辑比较单一,并不需要实现很多的装饰器,我们可以省略该类,直接写具体的装饰器(ConcreteComponentA…等)
- 具体装饰器(ConcreteComponentA…),decorator的实现类,每一个实现类都扩展类component组件的一个功能.
-
应用场景
下面以英雄联盟中李青(盲僧)学技能为例。其中Hero代表英雄(抽象构件)、BlindMonk(盲僧-具体构件)、SkillDecorator(技能-抽象装饰器)、QWERDecorator为英雄的四个技能(具体装饰器) -
场景实现
interface Hero {
void learnSkill();
}
class BlobMan implements Hero {
public String name ;
public BlobMan(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void learnSkill() {
System.out.println(getName());
}
}
interface SkillDecorator extends Hero{}
class QDecorator implements SkillDecorator {
private Hero hero;
private String name;
public QDecorator(Hero hero, String mame) {
this.hero = hero;
this.name = mame;
}
private void learnQ(){
System.out.println(" 习得技能" + name);
}
@Override
public void learnSkill() {
hero.learnSkill();
learnQ();
}
}
class WDecorator implements SkillDecorator {
private Hero hero;
public String name;
public WDecorator(Hero hero, String mame) {
this.hero = hero;
this.name = mame;
}
private void learnW(){
System.out.println(" 习得技能: " + name);
}
@Override
public void learnSkill() {
hero.learnSkill();
learnW();
}
}
public class Main {
public static void main(String[] args) {
BlobMan bm = new BlobMan("bolbman1");
bm.learnSkill();
Hero q = new QDecorator(bm, "w-大跳");
q.learnSkill();
Hero w = new WDecorator(bm,"W-大招" );
w.learnSkill();
System.out.println();
}
}
1.3.3. 代理模式
为其他对象提供一种代理以控制对这个对象的访问!代理对象具备真实对象的功能,并代替真实对象完成相应操作!
- 代理模式的分类
- 静态代理
- 动态代理
- CGLJB代理
- 静态角色组成
- 抽象角色: 一个接口/抽象类,规定了被代理对象中需要被代理对象的行为。
- 具体角色: :实现/继承抽象角色,实现抽象角色规定的中的行为逻辑!
- 代理角色: 代理真实角色,与真实角色实现同一个抽象角色, 代理角色中有一个真实角色的引用,在原有真实对象的行为基础上做扩展!使用户可以不用直接访问真实角色就可以通过代理对象实现相关逻辑行为!
-
静态代理应用场景
翻墙行为!我们日常上网是无法直接访问国外网站,需要代理服务!假设上网行为(service), 国内服务器 CService, 通过代理服务 OService, 此时我们就可以访问国外网站了! -
静态代理场景实现
interface Service {
void surfing();
}
class CService implements Service {
@Override
public void surfing() {
System.out.println(" -------------- 我是国内服务器 ---------------- ");
}
}
class QService implements Service {
Service service;
public QService(Service service) {
this.service = service;
}
@Override
public void surfing() {
service.surfing();
System.out.println(" 国内 ip 映射 外网 ip");
System.out.println(" -------------- 外网服务器 ---------------- ");
}
}
public class Main {
public static void main(String[] args) {
Service service = new CService();
Service oervice = new QService(service);
oervice.surfing();
}
}
-
动态代理
动态代理是在程序运行时,通过反射机制动态生成的代理类。Java提供了java.lang.reflect.Proxy类来实现动态代理。 -
动态代理场景实现
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 抽象接口
interface Service {
void surfing();
}
// 目标对象
class CService implements Service {
public void surfing() {
System.out.println("Performing operation in RealService");
}
}
// 动态代理处理器
class ServiceInvocationHandler implements InvocationHandler {
private Object target;
public ServiceInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" ----------- surfing 执行之前 --------- ");
Object result = method.invoke(target, args);
System.out.println(" ----------- surfing 执行之后 --------- ");
return result;
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
CService realService = new CService();
ServiceInvocationHandler handler = new ServiceInvocationHandler(realService);
Service proxy = (Service) Proxy.newProxyInstance(realService.getClass().getClassLoader(),
new Class<?>[]{Service.class},
handler);
proxy.surfing();
}
}
1.3.4. 外观模式
提供了一个统一的接口,用来访问子系统中的一群接口的模式。换句话说,外观模式就像是一个简洁的控制面板,隐藏了复杂的内部实现,让使用者只需通过简单的操作即可完成复杂的任务。
- 角色组成
- 外观(Facade): 提供了访问子系统一组接口的统一接口,并将客户端请求委派给相应的子系统对象处理。
- 子系统(SubSystem): :实现了子系统的具体功能,处理来自外观对象的请求。
-
应用场景
我们外出旅游时,可以直接找旅游公司报名某一旅游活动而不用关心车票、景区门票、酒店门票等流程! -
java 场景实现
interface TravelFacade {
boolean depart();
}
class ScenicSpotTools{
public void bookTiket(){
System.out.println("------------ 预定 景区 门票 ----------------");
}
}
class TransportTools{
public void bookTransportation(){
System.out.println("------------ 预定 高铁 车票 ----------------");
}
}
class HotelTools{
public void bookTiket(){
System.out.println("------------ 预定 酒店 门票 ----------------");
}
}
class MyTravelFacade implements TravelFacade {
HotelTools hotelTools;
TransportTools transportTools;
ScenicSpotTools scenicSpotTools;
public MyTravelFacade(){
this.hotelTools = new HotelTools();
this.transportTools =new TransportTools();
this.scenicSpotTools =new ScenicSpotTools();
}
public boolean depart(){
System.out.println("------------ 开始行程 ----------------");
this.hotelTools.bookTiket();
this.transportTools.bookTransportation();
this.scenicSpotTools.bookTiket();
return true;
}
}
public class Main{
public static void main(String[] args) {
TravelFacade myTravelFacade=new MyTravelFacade();
myTravelFacade.depart();
}
}
1.3.5. 桥接模式
将抽象部分和实现部分分离,使它们可以独立地变化。
- 抽象部分(Abstraction):定义了抽象部分的接口,并包含对实现部分的引用。
- 实现部分(Implementor):定义了实现部分的接口。
- 具体抽象(Concrete Abstraction):继承抽象部分,实现其中定义的抽象方法。
- 具体实现(Concrete Implementor):实现Implementor,实现其中定义的具体行为。
-
应用场景
下面是一个蓝牙耳机和手机的简单例子,用来解释桥接模式。手机作为抽象部分,蓝牙耳机作为实现部分。通过抽象类对实现类接口的引用,使手机可以调用蓝牙接口的方法,实现手机与蓝牙耳机的连接和调用的解耦。 -
场景实现
interface BlueTooth {
void connected();
void disconnected();
}
class BlueToothImpl implements BlueTooth{
@Override
public void connected() {
System.out.println("蓝夜以链接..............");
}
@Override
public void disconnected() {
System.out.println("蓝夜以断开..............");
}
}
interface Phone {
void operateBlueTooth();
}
class IPhone implements Phone{
BlueTooth blueTooth;
public IPhone(BlueTooth blueTooth) {
this.blueTooth = blueTooth;
}
@Override
public void operateBlueTooth() {
System.out.println(" IPhone 链接操作................. ");
this.blueTooth.connected();
this.blueTooth.disconnected();
}
}
class HPhone implements Phone{
BlueTooth blueTooth;
public HPhone(BlueTooth blueTooth) {
this.blueTooth = blueTooth;
}
@Override
public void operateBlueTooth() {
System.out.println(" HPhone 链接操作................. ");
this.blueTooth.connected();
this.blueTooth.disconnected();
}
}
public class Main{
public static void main(String[] args) {
BlueTooth blueTooth = new BlueToothImpl();
Phone hp =new HPhone(blueTooth);
Phone ip =new IPhone(blueTooth);
ip.operateBlueTooth();
hp.operateBlueTooth();
}
}