Java设计模式
java 设计模式
命令模式
对原理类图的说明一即(命名模式的角色及职责)
1) Invoker 是调用者角色 2) Command:是命令角色,需要执行的所有命令都在这里,可以是接口或抽象类
3)Recever·接受者角色产知道如何实施和执行个请求相关的操作 4) ConcreteCommand:将一个接受者对象与一个动作绑定,调用接受者相应的操作,实现 execute
实例-亮点:空命令
类图
观察者模式
类图
Subject
Subject(被观察者)是可以登记注册,移除,通知的一方。它具有者几个功能
Observer
observer,属于接收输入这一方,属于观察者。用户是属于 observer,多对 1 里多的一方。
功能就是更新信息。
总类图
weatherData 气象站,首先它实现了 subject 接口,并且它会聚合很多的观察者,所以有聚合按钮,所以先写 observer,再写 wetherdata。
然后 subject 使用到了 observer(不管是登录注册,移除,都用到了 observer)
接着,百度新浪等网站,都实现了,observer 接口,充当观察者(也就是被通知那一方)
观察者模式在 JDK 应用的源码分析
其实简化了很多,很好用
关键点。
observable 等价于 subject
不过前者是一个类,后者是一个接口
而 observer 本来就是等价于 observer(观察者)有 update 方法
jdk 例子-单刀赴会
被观察者 Lusu
package model.Observer.DanDaoFuHui;
import java.util.Observable;
/**
* 是主题
*/
public class Lusu extends Observable {
//鲁肃摔酒杯
public void throwCup(){
System.out.println("鲁肃摔杯!");
//说明状态发生变化
this.setChanged();
//通知所有人
this.notifyObservers();
}
}
观察者,killer
package model.Observer.DanDaoFuHui;
import java.util.Observable;
import java.util.Observer;
/**
* 这是观察者(单刀赴会)
*/
public class Killer implements Observer {
private String name;
public Killer(String name,Observable o){
this.name = name;
//刀手听命于鲁肃,加到听命列表里
o.addObserver(this);
}
private void kill(){
System.out.println(name + "杀关羽!");
}
//实现这个方法
@Override
public void update(Observable o, Object arg) {
this.kill();
}
}
测试类
package model.Observer.DanDaoFuHui;
/**
*测试
*/
public class TestLusu {
public static void main(String[] args) {
Lusu lusu = new Lusu();
Killer killer1 = new Killer("k1",lusu);
Killer killer2 = new Killer("k2",lusu);
Killer killer3 = new Killer("k3",lusu);
Killer killer4 = new Killer("k4",lusu);
Killer killer5 = new Killer("k5",lusu);
lusu.throwCup();
}
}
运行结果
装饰模式
实例-核心:动态扩展
关于 oo
https://blog.csdn.net/ql15010832315/article/details/53127724
核心点在于动态扩展
方案 2
引出装饰者模式
定义
原理
uml 类图(原理)
实例 2-扫地机器人
实例 uml
代码
架构
实际代码
package model.decoration.Robot;
/**
*
*/
public class CleanRobot{
public void work(){
System.out.println("扫地!");
}
}
package model.decoration.Robot;
/**
*
*/
public class Function extends CleanRobot{
private CleanRobot cleanRobot = null;
public Function(CleanRobot cleanRobot){
this.cleanRobot = cleanRobot;
}
public void work(){
if(cleanRobot!=null){
cleanRobot.work();
}
}
}
package model.decoration.Robot;
/**
*
*/
public class JudgeFunction extends Function{
public JudgeFunction(CleanRobot cleanRobot) {
super(cleanRobot);
}
public void work(){
System.out.println("判断地面很脏,开始打扫");
super.work();
}
}
package model.decoration.Robot;
/**
*
*/
public class SpeakFunction extends Function{
public SpeakFunction(CleanRobot cleanRobot) {
super(cleanRobot);
}
public void work(){
System.out.println("主人!我要开始工作了哦!");
super.work();
}
}
package model.decoration.Robot;
/**
*
*/
public class TestCleanRobot {
public static void main(String[] args) {
CleanRobot cleanRobot = new CleanRobot();
System.out.println("===动态扩展前===");
cleanRobot.work();
System.out.println("===动态扩展后===");
cleanRobot = new SpeakFunction(cleanRobot);
cleanRobot = new JudgeFunction(cleanRobot);
cleanRobot.work();
}
}
运行结果
代理模式
静态代理
导例
代理模式的结构
◆ 抽象主题(Subject)
◆ 实际主题( RealSubject)
◆ 代理(Proxy)
uml 图
特点:客户代码只和代理主题打交道,无法接触到真实主题,(而真实主题是具体的执行者,代理负责创建真实主题并且它的方法)
三角形计算面积的代码实例
- 接口类
package model.Proxy.staticProxy;
/**
* 几何类,这是代理模式的接口类
*/
public interface Geometry {
//需要有一个计算面积的方法,返回double数值
public double getArea();
}
- 真实主题
package model.Proxy.staticProxy;
/**
* 三角形,真实主题
*/
public class Triangle implements Geometry {
double sideA,sideB,sideC,area;
//初始化三角形的三条边
public Triangle(double a ,double b,double c){
sideA = a;
sideB = b;
sideC = c;
}
@Override
public double getArea() {
//直接计算,只需要计算就好啦,判断啥的交给代理来做。
//海伦公式计算面积。
double p = (sideA+sideB+sideC)/2;
area = Math.sqrt(p*(p-sideA)*(p-sideB)*(p-sideC));
return area;
}
}
- 代理主题
package model.Proxy.staticProxy;
/**
* 代理主题,这里直接代理了原来的三角形
*/
public class ProxyTriangle implements Geometry{
double sideA,sideB,sideC,area;
//引入真实主题
Triangle triangle;
//先获取三条边
public void setTriangle(double a,double b ,double c){
//初始化
sideA = a;
sideB = b;
sideC = c;
}
@Override
public double getArea() {
//先判断两边之和大于第三边
if(sideA+sideB>sideC&&sideA+sideC>sideB&&sideC+sideB>sideA){
//给原来引入的三角形初始化
triangle = new Triangle(sideA,sideB,sideC);
area = triangle.getArea();
return area;
}else {
return -1;
}
}
}
- 测试
package model.Proxy.staticProxy;
import java.util.Scanner;
/**
* 测试代理模式计算三角形的面积
*/
public class Test {
public static void main(String[] args) {
ProxyTriangle proxyTriangle = new ProxyTriangle();
proxyTriangle.setTriangle(3,4,5);//符合
System.out.println(proxyTriangle.getArea());
proxyTriangle.setTriangle(3,1,5);//不符合
System.out.println(proxyTriangle.getArea());
//或者自己输入
Scanner reader = new Scanner(System.in);
System.out.println("请输入三个数,每输入一个数回车确认");
double a = -1 ,b = -1 ,c = -1;
a = reader.nextDouble();
b = reader.nextDouble();
c = reader.nextDouble();
proxyTriangle.setTriangle(a,b,c);
double area = proxyTriangle.getArea();
System.out.println("面积是:"+area);
}
}
- 运行结果
6.0
-1.0
请输入三个数,每输入一个数回车确认
6
8
10
面积是:24.0
动态代理
前置知识
依然是三角形计算面积实例
- 抽象代理接口类
package model.Proxy.dynamicProxy;
/**
* 几何类,这是代理模式的接口类
*/
public interface Geometry {
//需要有一个计算面积的方法,返回double数值
public double getArea();
//需要获取三条边
public double getSideA();
public double getSideB();
public double getSideC();
}
- 真实主题实现类
package model.Proxy.dynamicProxy;
/**
* 三角形,真实主题
*/
public class Triangle implements Geometry {
double sideA,sideB,sideC,area;
//初始化三角形的三条边
public Triangle(double a ,double b,double c){
sideA = a;
sideB = b;
sideC = c;
}
@Override
public double getArea() {
//直接计算,只需要计算就好啦,判断啥的交给代理来做。
//海伦公式计算面积。
double p = (sideA+sideB+sideC)/2;
area = Math.sqrt(p*(p-sideA)*(p-sideB)*(p-sideC));
return area;
}
public double getSideA() {
return sideA;
}
public double getSideB() {
return sideB;
}
public double getSideC() {
return sideC;
}
}
- 代理对象的调用请求类
package model.Proxy.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理对象的调用请求者
* 1.需要实现调用处理接口
*/
public class TriangleHandle implements InvocationHandler {
//引入抽象代理对象
Geometry g;
//初始化
public TriangleHandle(Geometry geometry){
g = geometry;
}
//调用方法(当前的代理对象,它的方法,它的参数)
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//如果方法为getArea,则先进行判断,也就是前置操作
//需要获取三边的值,故,Geometry需要三个get方法。
/*
思考
但是方法里边是可以创建对象的,不理解为什么要特意用个get方法,觉得大可不必。
如果方法创建对象赋值,a,b,c就得在当前的处理类定义属性,来赋值,嗯,也是有点麻烦,主要是不够灵活
因为不只是计算面积,还有其他方法也可以用在本例。
*/
double a = g.getSideA();
double b = g.getSideB();
double c = g.getSideC();
double result = 0;//返回的结果数值,不定义为area是因为,其他方法会返回其他名称的数值,不如用result统一返回结果
//获取当前的方法咯
if(method.getName().equals("getArea")){
if(a+b>c&&a+c>b&&c+b>a){
result = (double) method.invoke(g,args);//因为method.invoke返回的结果是对象,所以需要强制转型为double
}else {
result = -1;
}
}
return result;
}
//获取当前的代理对象
public Object getProxy(){
//参数是,类的装载对象,类的代理接口,类的代理对象的调用请求者
Object o = Proxy.newProxyInstance(g.getClass().getClassLoader(), g.getClass().getInterfaces(), this);
// System.out.println("getClassLoader()===>"+g.getClass().getClassLoader());//sun.misc.Launcher$AppClassLoader@14dad5dc
// System.out.println("getInterfaces()===>"+g.getClass().getInterfaces());//[Ljava.lang.Class;@2503dbd3
// System.out.println("this===>"+this); //model.Proxy.dynamicProxy.TriangleHandle@4b67cf4d
return o;
}
}
- 测试类
package model.Proxy.dynamicProxy;
/**
* 动态代理技术的测试,依然是计算三角形的面积
*
* 理解:
* 抽象代理接口只管定义和执行即可,而具体执行的前置操作和后置操作(各种判断,都是我们动态代理帮你做)
*
* 而动态代理和静态代理的区别?
* 动态代理只管和抽象主题做对接(扩展性更强,在方法上也更灵活)
* 静态代理管的是和真实主题的对接
*/
public class Test {
public static void main(String[] args) {
//首先需要具体的抽象代理接口
Geometry g = new Triangle(3, 4, 5);
//代理对象的调用请求者
TriangleHandle h = new TriangleHandle(g);
//获取当前的代理对象
Geometry proxy = (Geometry) h.getProxy();
double area = proxy.getArea();//这个时候才执行invoke方法。
System.out.println("面积为:"+area);
}
}
- 运行结果
面积为:6.0
扩展:xml
知识点转载
xml简介
XML 被设计用来传输和存储数据。
HTML 被设计用来显示数据。
XML 指可扩展标记语言(eXtensible Markup Language)。
可扩展标记语言(英语:Extensible Markup Language,简称:XML)是一种标记语言,是从标准通用标记语言(SGML)中简化修改出来的。它主要用到的有可扩展标记语言、可扩展样式语言(XSL)、XBRL 和 XPath 等。
定义
- XML 指可扩展标记语言(EXtensible Markup Language)。
- XML 是一种很像 HTML 的标记语言。
- XML 的设计宗旨是传输数据,而不是显示数据。
- XML 标签没有被预定义。您需要自行定义标签。
- XML 被设计为具有自我描述性。
- XML 是 W3C 的推荐标准。
XML 和 HTML 之间的差异
XML 不是 HTML 的替代。
XML 和 HTML 为不同的目的而设计:
- XML 被设计用来传输和存储数据,其焦点是数据的内容。
- HTML 被设计用来显示数据,其焦点是数据的外观。
HTML 旨在显示信息,而 XML 旨在传输信息。
xml 性质
- XML 不会做任何事情
也许这有点难以理解,但是 XML 不会做任何事情。XML 被设计用来结构化、存储以及传输信息。
下面实例是 Jani 写给 Tove 的便签,存储为 XML:
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
上面的这条便签具有自我描述性。它包含了发送者和接受者的信息,同时拥有标题以及消息主体。
但是,这个 XML 文档仍然没有做任何事情。它仅仅是包装在 XML 标签中的纯粹的信息。我们需要编写软件或者程序,才能传送、接收和显示出这个文档。
- 通过 XML 您可以发明自己的标签
上面实例中的标签没有在任何 XML 标准中定义过(比如
这是因为 XML 语言没有预定义的标签。
HTML 中使用的标签都是预定义的。HTML 文档只能使用在 HTML 标准中定义过的标签(如 <p>、<h1> 等等)。
XML 允许创作者定义自己的标签和自己的文档结构。
- XML 不是对 HTML 的替代
XML 是对 HTML 的补充。
XML 不会替代 HTML,理解这一点很重要。在大多数 Web 应用程序中,XML 用于传输数据,而 HTML 用于格式化并显示数据。
对 XML 最好的描述是:
XML 是独立于软件和硬件的信息传输工具。
xml 的作用
XML 应用于 Web 开发的许多方面,常用于简化数据的存储和共享
- XML 把数据从 HTML 分离
- XML 简化数据分享
- XML 简化数据传输
- XML 简化平台变更
- XML 使您的数据更有用
- XML 用于创造新的互联网语言
我们为什么要运用 XML?
xml 具有的能够运行于不同系统平台之间和转换成不同格式目标文件的能力使得它成为内容管理应用系统中的优秀选择
xml 的结构图
标准的 xml 格式
- 有且只有一个根元素
- XML 标签大小写正确区分
- 正确使用结束标签
- 正确嵌套标签
- 使用了合法的标签名
- 定义有效的属性
元素定义
- 元素的分类
1.空元素
<!ELEMENT element-name EMPTY> //空元素
2.文本元素
<!ELEMENT element-name (#PCDATA)>//文本元素
3.混合元素
<!ELEMENT element-name(e1,e2)> //混合元素
- 元素的限制
与(,) 非(|)
次数分为:
0 或 1 | 用?号表示 |
---|---|
0~N | 用*号表示 |
1~N | 用+号表示 |
- 案例
属性定义
语法:
<!ATTLIST element-name att_name type desc>
-
属性类型 type
ID:写元素的话必须要写这个
(男|女) :只能填男或者女
CDATA:文本属性
IDREF:引用别人 ID 中的值
reference(少用) -
属性描述
REQUIRED:必填
IMPLIED:非必填
'默认值'
注意:只有 type 为(男|女)类型时,desc 才可以使用默认值的方式
案例
读取 xml 文件
作业实践
-
UML 类图
-
框架代码实现
-
架构(maven 项目)
-
接口类
package lovi.homework; /** * 行为接口,定义看剧和体测800米的行为 */ public interface Action { public void watching(); public void running(); }
- 接口实现类
package lovi.homework; /** * 行为实现 */ public class ActionImpl implements Action{ @Override public void watching() { System.out.println("正在追剧!!!"); } @Override public void running() { System.out.println("正在800米体测!!!"); } }
4.操作类(前置操作和后置操作)
package lovi.homework; /** * 方法的前置操作和后置操作 */ public class Operation { //看剧的前后置 public void preWatch() { System.out.println("看剧之前准备小零食"); } public void afterWatch() { System.out.println("看剧之后和朋友分享观后感"); } //体测800米的前后置 public void preRun() { System.out.println("体测800米之前正在热身"); } public void afterRun() { System.out.println("体测800米之后上交身份证录入成绩"); } }
- pom 依赖
<!--用dom4j读取xml文件的依赖--> <dependencies> <dependency> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> <version>2.1.1</version> </dependency> </dependencies>
- xml 文件(放在 resource 下)
<?xml version="1.0" encoding="UTF-8"?> <proxys> <proxy id="actionProxy" class="lovi.homework.ActionImpl"> <method name="watching"> <prefix bean="lovi.homework.Operation" mtd="preWatch" /> <suffix bean="lovi.homework.Operation" mtd="afterWatch" /> </method> <method name="running"> <prefix bean="lovi.homework.Operation" mtd="preRun" /> <suffix bean="lovi.homework.Operation" mtd="afterRun" /> </method> </proxy> </proxys>
- 代理对象的调用请求处理类
package lovi.homework; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; import java.io.File; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 动态代理 * 行为代理调用请求处理类 */ public class ActionHandle implements InvocationHandler { private Class Served;//真实主题类(也就是被代理的类,就是被服务的类)Served private Element myProxy;//被代理类的元素 //首先获取负责代理的类(根据id获取) public Object getProxy(String id){ try { File f = new File("src/main/resources/proxy.xml"); Document doc = new SAXReader().read(f); Element root =doc.getRootElement();//获取xml的根节点 //遍历每一个子节点,也就是每个proxy,有对应的id和其他的被代理的类名 for(Element element : root.elements()){ //找需要的proxy if(element.attributeValue("id").equals(id)){ myProxy = element; Served = Class.forName(myProxy.attributeValue("class")); } } } catch (Exception e) { e.printStackTrace(); } //返回代理类 return Proxy.newProxyInstance(Served.getClassLoader(), Served.getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Element myMethod1 = myProxy.elements().get(0); String method1Name = myProxy.elements().get(0).attributeValue("name");//whatching Element myMethod2 = myProxy.elements().get(1); String method2Name = myProxy.elements().get(1).attributeValue("name");//running if(method.getName().equals(method1Name)){ String bean11 = myMethod1.elements().get(0).attributeValue("bean"); String mtd11 = myMethod1.elements().get(0).attributeValue("mtd"); String bean12 = myMethod1.elements().get(1).attributeValue("bean"); String mtd12 = myMethod1.elements().get(1).attributeValue("mtd"); //执行前置操作 Object object11 = Class.forName(bean11).newInstance(); Method method1 = object11.getClass().getDeclaredMethod(mtd11); method1.invoke(object11); //执行方法 method.invoke(Served.newInstance(), args); //执行后置操作 Object object12 = Class.forName(bean12).newInstance(); Method method01 = object12.getClass().getDeclaredMethod(mtd12); method01.invoke(object12); }else if(method.getName().equals(method2Name)){ String bean21 = myMethod2.elements().get(0).attributeValue("bean"); String mtd21 = myMethod2.elements().get(0).attributeValue("mtd"); String bean22 = myMethod2.elements().get(1).attributeValue("bean"); String mtd22 = myMethod2.elements().get(1).attributeValue("mtd"); //前置操作 Object object21 = Class.forName(bean21).newInstance(); Method method2 = object21.getClass().getDeclaredMethod(mtd21); method2.invoke(object21); //执行方法 method.invoke(Served.newInstance(), args); //后置操作 Object object22 = Class.forName(bean22).newInstance(); Method method02 = object22.getClass().getDeclaredMethod(mtd22); method02.invoke(object22); } return null; } }
-
-
框架代码测试
-
测试类
-
package lovi.homework; /** * */ public class Test { public static void main(String[] args) { Action action = new ActionImpl(); ActionHandle handle = new ActionHandle(); action = (Action) handle.getProxy("actionProxy"); action.watching(); System.out.println("======="); action.running(); } }
-
-
运行结果
-
单例模式
Singleton.java
package com.dzxcqmxm.pattern.singleton;
/**
* 唯一的登录框
* 懒汉式单例模式
*/
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void one(int div){
if(div==1){
System.out.println("保证唯一的登录框框!");
}
}
}
TestSingleton
package com.dzxcqmxm.pattern.singleton;
/**
* 单例模式测试,一个登录框框
*/
public class TestSingleton {
public static void main(String[] args) {
//获取唯一的可用对象
Singleton s = Singleton.getInstance();
//保证唯一的窗口
s.one(1);
}
}
模板模式
FenLei
public class FenLei extends Template{
@Override
String getType() {
return "系统相册分类";
}
}
ShenHe
public class ShenHe extends Template{
@Override
String getType() {
return "审核";
}
}
Template
public abstract class Template {
public String show(){
return "这是"+getType()+"页面";
}
abstract String getType();//需要实现的具体的动态变化的内容
}
testTemplate
/**
* 模板模式
*/
public class testTemplate {
public static void main(String[] args) throws IOException {
Template s = new ShenHe();
System.out.println(s.show());
}
}
运行结果
工厂模式
- 主题接口
ColorTheme
/**
* 主题,可以有粉色主题,也可以默认主题,也可以是黄色主题
*/
public interface ColorTheme {
public String getColor();
}
- 三个不同主题实现接口
DefaultColor
/**
* 默认颜色#b0f9dc
*/
public class DefaultColor implements ColorTheme{
@Override
public String getColor() {
return "#b0f9dc";
}
}
Pink
/**
* 粉色主题
*/
public class Pink implements ColorTheme{
@Override
public String getColor() {
return "#FFE4E1";
}
}
Yellow
/**
* 黄色主题
*/
public class Yellow implements ColorTheme{
@Override
public String getColor() {
return "#ffff99";
}
}
- 主题生产工厂
ThemeFactory
/**
* 主题工厂,用户可以选择创建不同的色系主题
* 可以来个粉色和黄色的
*
*/
public class ThemeFactory {
public static ColorTheme getThemeColor(String color){
ColorTheme a = null;
if("#FFE4E1".equals(color)){
a = new Pink();
}else if("#ffff99".equals(color)){
a = new Yellow();
}else {
a = new DefaultColor();
}
return a;
}
}
- 测试
TestFactory
package com.dzxcqmxm.pattern.factory;
import javax.swing.*;
/**
* 简单工厂模式
*/
public class TestFactory {
//封装成工具类(挺好的,就是jsp不能用JOptionPane)
public static String getColor(String s){
// Object[] options = {"default", "yellow", "pink"};
// String s = (String) JOptionPane.showInputDialog(null, "选择你想要的主题", "主题选择",
// JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
String a = null;
if("pink".equals(s)){
a = "#FFE4E1";
}else if("yellow".equals(s)){
a = "#ffff99";
}else {
a = "#b0f9dc";
}
ColorTheme colorTheme = ThemeFactory.getThemeColor(a);
System.out.println(colorTheme.getColor());
return colorTheme.getColor();
}
public static void main(String[] args) {
//测试
TestFactory.getColor("pink");
}
}
- 运行结果
策略模式
- 策略接口
LoginStrategy
package com.dzxcqmxm.pattern.strategy;
public interface LoginStrategy {
public void login(String a, String b);
}
- 不同的策略实现接口
AdministratorLogin
package com.dzxcqmxm.pattern.strategy;
/**
*
*/
public class AdministratorLogin implements LoginStrategy{
//管理员登陆
@Override
public void login(String a, String b) {
if("admin".equals(a)&&"admin".equals(b)){
System.out.println("管理员登录成功!!");
}
}
}
UserLogin
package com.dzxcqmxm.pattern.strategy;
/**
*
*/
public class UserLogin implements LoginStrategy{
//定义两个数据库里拿到的值
private String a="张三";
private String b="123456";
@Override
public void login(String a, String b) {
if (this.a.equals(a)&&this.b.equals(b)){
System.out.println("用户登录成功!");
}
}
}
- 上下文对象一个对所有策略实现管理
Context
package com.dzxcqmxm.pattern.strategy;
/**
* 上下文对象
*/
public class Context {
private LoginStrategy ls;
public Context(LoginStrategy ls){
this.ls=ls;
}
public void executeLoginStrategy(String a,String b){
ls.login(a,b);
}
}
- 测试
TestLoginSt
package com.dzxcqmxm.pattern.strategy;
/**
* 策略模式
*/
public class TestLoginSt {
public static void main(String[] args) {
//管理员登录策略
Context context = new Context(new AdministratorLogin());
context.executeLoginStrategy("admin","admin");
//用户登录策略
context = new Context(new UserLogin());
context.executeLoginStrategy("张三","123456");
}
}
- 运行结果
建造者模式
中介者模式
- 房屋中介
适配器模式
武松鲁达当和尚
组合模式
IT 公式组合模式
状态模式
先画状态转换图
uml
可乐机
- 状态图
教师改良版
- 类图
责任链模式
- 菜鸟
- 击鼓传花
- 红心游戏
桥接模式
- 猪八戒投胎
- 电视台放节目