1.建造者模式
角色:抽象构造者,具体构造者,产品,指挥者。
//产品
public class Actor
{
private String type, sex, face, costume, hairstyle;
}
//抽象构造者
public abstract class ActorBuilder {
protected Actor actor = new Actor();
public abstract void buildType();
public abstract void buildSex();
public abstract void buildFace();
public abstract void buildCostume();
public abstract void buildHairStyle();
public Actor create() {
return actor;
}
}
//具体构造者
public class AngleBulder extends ActorBuilder {
public void buildType() {
actor.setType("天使");
}
public void buildSex() {
actor.setSex("女");
}
public void buildFace() {
actor.setFace("美");
}
public void buildCostume() {
actor.setCostume("长裙");
}
public void buildHairStyle() {
actor.setHairstyle("长发");
}
}
public class HeroBulder extends ActorBuilder {
public void buildType() {
actor.setType("英雄");
}
public void buildSex() {
actor.setSex("男");
}
public void buildFace() {
actor.setFace("帅");
}
public void buildCostume() {
actor.setCostume("重甲");
}
public void buildHairStyle() {
actor.setHairstyle("长发");
}
}
//控制器,根据不同的构造者,采用不同的构造方式进行构造
public class ActorController {
public Actor construct(ActorBuilder ab) {
ab.buildCostume();
ab.buildFace();
ab.buildHairStyle();
ab.buildSex();
ab.buildType();
return ab.create();
}
}
//调用方
public class Main {
public static void main(String args[]){
XmlUtil util=new XmlUtil("builder//config.xml");
ActorBuilder ab=(ActorBuilder)util.getBean();
ActorController ac=new ActorController();
Actor actor = ac.construct(ab);
System.out.println(actor);
}
}
优点:
1.客户端不需要知道产品的内部组成细节,将产品和创建过程解耦,相同的创建过程创建不同的创建对象
2.每个builder独立,可以方便的增加替换buide,增加新的builder无需修改类库代码,符合开闭原则
3.精细的控制产品创建过程,控制创建时序
缺点
1.创建的产品有共同点,组成部分相似
2.如果产品内部变化大,会产生大量的builder
2.适配器模式
角色:
1.Target:客户所期待的接口,可以是具体抽象类,或接口
2.Adapter(适配器):包装适配对象,转换为目标接口
3.Adaptee(适配者):需要适配的对象或类
用途:
1.系统要调用一些类,这些类的接口不符合系统需要,或者这些类没有源码,无法直接调用。
2.想创建一个可以重复工作的类,用于和一些彼此没有关联的类一起工作
类适配器
//被适配的类,网线
class Adapte {
public void request() {
System.out.println("连接网线上网");
}
}
//客户端:电脑,想上网,但电脑无法直接使用网线
//所以,电脑需要转接口上网
class Computer {
public void net(NetUSB adapter) {
adapter.handler();
}
}
//接口转换器
interface NetUSB {
public void handler();
}
//转接口实现
class Adapter extends Adapte implements NetUSB {
public void handler() {
//通过继承访问网线的功能
request();
}
}
public class Main {
public static void main(String a[]){
Computer computer=new Computer();
computer.net(new Adapter());
}
}
对象适配器
讲继承改为组合
class Adapter implements NetUSB
{
private Adapte adapte;
public Adapter(Adapte adapte){this.adapte=adapte;}
public void handler() {
adapte.request();
}
}
对象适配器的优点:
1.一个适配器把多个适配者适配到同一个目标
2.adapter可以适配适配者adapte的子类,符合里氏替换原则
类适配器缺点:
Java单继承,1个adapter只能适配一个适配者adapte
适用场景:
1.类的接口不满足系统规范,或者没有类的源代码
2.想创建一个可复用的类,用来和一些没有太大关联的类一起工作
系统应用:
java AWT中的事件适配器:
public interface KeyListener extends EventListener {
public void keyTyped(KeyEvent e);
public void keyPressed(KeyEvent e);
public void keyReleased(KeyEvent e);
}
//该接口的空实现
public abstract class KeyAdapter implements KeyListener {
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
}
通过继承KeyAdapter可以实现监听键盘的部分事件
3.桥接器模式
角色:抽象类,扩充抽象类,Implementor ,ConcreteImplementor
//电脑有不同的形式:台式,笔记本,云电脑
//同时电脑也有不同的牌子苹果,戴尔,联想
//如果适用多继承,将要维护1+3+9=13个类
//使用桥接器模式的话,能将类的数量减少到6个子类,2个抽象类
interface Brand{
public void info();
}
class Lenvo implements Brand{
public void info() {
System.out.println("联想");
}
}
//将电脑类型和品牌连接的桥梁
//电脑种类增加不影响品牌
//品牌种类增加不影响电脑
abstract class Computer{
protected Brand brand;
public Computer(Brand b){
brand=b;
}
public void info() {
brand.info();
}
}
class DeskTop extends Computer{
public DeskTop(Brand b) {
super(b);
}
@Override
public void info() {
super.info();
System.out.println("台式机");
}
}
class LabTop extends Computer{
public LabTop(Brand b) {
super(b);
}
@Override
public void info() {
super.info();
System.out.println("笔记本");
}
}
public class Main {
public static void main(String[] args){
Computer c=new DeskTop(new Lenvo());
c.info();
Computer c2=new LabTop(new Lenvo());
c.info();
}
}
好处
1. 一种替代多继承的方案,多继承违背了单一职责的原则
2. 提高了系统的可扩充性,扩展维度不需要修改系统,符合开闭,只需要一道桥把两个维度连接起来
坏处
1. 聚合关联在抽象层,增加系统理解难度
2. 正确识别出两个变化的维度
使用情况
1.减少多继承子类的数量
2.需要在抽象化角色和具体角色之间增加灵活性,动态的将抽象化子类和实现化子类进行组合。
3.一个系统有两个独立变化的维度
4.组合模式
将对象组合成树状结构,使用户对单个对象和组合对象的访问有一致性
角色
1.Component
2.Leaf
3.Composit
java awt UI框架模仿
//UI组件抽象
abstract class Component{
protected abstract void show();
}
//UI容器,同时也是UI组件的一种
abstract class Container extends Component{
List<Component> sons=new ArrayList<>();
protected void add(Component component){
sons.add(component);
};
protected void remove(Component component){
sons.remove(component);
};
}
//窗口,对话框,块级元素都是容器节点的一种
class Window extends Container{
@Override
protected void show() {
System.out.print("Window {\n");
for(Component item:sons)item.show();
System.out.print("}\n");
}
}
class Diolog extends Container{
@Override
protected void show() {
System.out.print("Diolog {\n");
for(Component item:sons)item.show();
System.out.print("}\n");
}
}
class Panel extends Container{
@Override
protected void show() {
System.out.print("Panel {\n");
for(Component item:sons)item.show();
System.out.print("}\n");
}
}
//按钮,选项框都是叶子UI节点
class Button extends Component{
@Override
protected void show() {
System.out.print("Button\n");
}
}
class CheckBox extends Component{
@Override
protected void show() {
System.out.print("CheckBox\n");
}
}
public class Main {
public static void main(String[] args){
Container window=new Window();
Container plan1=new Panel();
Container plan2=new Panel();
Container plan3=new Panel();
window.add(plan1);
window.add(plan2);
window.add(plan3);
plan1.add(new Button());
plan1.add(new CheckBox());
plan2.add(new Button());
window.show();
}
}
打印的结果
Window {
Panel {
Button
CheckBox
}
Panel {
Button
}
Panel {
}
}
优点
1.方便控制层次结构
2.客户端不需区分是组合结构还是单个对象,只用冯文conpoment即可
3.新增加新的容器节点或者叶子节点都不用修改类库,符合OCP
缺点
难以对容器中的构件类型做限制,如只允许该对话框里有按钮元素
5.外观模式
角色
1.外观角色:客户端调用该角色的api,该角色将请求转移给子系统处理
2.子系统角色:被外观角色或客户端调用
import java.io.FileInputStream;
import java.io.FileOutputStream;
class FileReader{
public String read(String url){
System.out.print("读文件,获取明文: ");
StringBuilder sb=new StringBuilder();
try {
FileInputStream inFS=new FileInputStream(url);
int data;
while((data=inFS.read())!=-1)
{
sb.append((char)data);
}
inFS.close();
System.out.println(sb.toString());
} catch (Exception e) {
System.out.println(e.toString());
}
return sb.toString();
}
}
class Encoder{
public String encode(String msg){
System.out.print("数据加密 ");
String res="";
for (int i = 0; i <msg.length() ; i++) {
res+=String.valueOf(msg.charAt(i)%7);
}
System.out.println(res);
return res;
}
}
class FileWriter{
public void write(String str,String url){
System.out.print("保存文件 ");
try {
FileOutputStream of=new FileOutputStream(url);
of.write(str.getBytes());
of.close();
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
//门面类
class Facade{
private FileReader fr=new FileReader();
private Encoder encoder=new Encoder();
private FileWriter fw=new FileWriter();
public void encodeFile(String url)
{
String str=fr.read(url);
str= encoder.encode(str);
fw.write(str,url);
}
}
public class Main {
public static void main(String[]a){
Facade facade=new Facade();
facade.encodeFile("D:\\考研\\设计模式源代码\\src\\main\\java\\facade\\myfile");
}
}
好处:
1.屏蔽子系统的细节,子系统更容易扩展
2.更好的划分访问层次
3.当遗留系统十分难以维护的时候,可以定义外观接口,保留系统的简单接口,增加可维护性
坏处:
1.不能限制客户端直接调用子系统类
2.增加新子系统可能要修改类库中外观类的代码,违反开闭原则
6.享元模式
角色
1.抽象享元:定义对象的外部状态和内部状态
2.具体享元
3.非共享具体享元:不会出现在享元工厂中
4.享元工厂:根据内部状态返回享元对象
案例:五子棋游戏
//Flyweight工厂,输入Flyweight的内部状态,返回一个Flyweight
class ChessFactory {
private static ChessFactory instance = new ChessFactory();
private static Hashtable<String, Chess> ht;//享元池,用于共享的对象
public static ChessFactory getInstance(){
return instance;
}
private ChessFactory() {
ht=new Hashtable<>();
ht.put("w", new WiteChess());
ht.put("b", new BlackChess());
}
//根据内部状态颜色,返回棋子
Chess getChese(String type) {
return ht.get(type);
}
}
class Pos {
private int x, y;
public Pos(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "Pos{" +
"x=" + x +
", y=" + y +
'}';
}
}
//抽象的Flyweight
//外部状态:棋子的位置POS,内部状态棋子的颜色
abstract class Chess {
public abstract Color getColor();
public void display(Pos pos, Graphics g) {
g.setColor(getColor());
g.fillOval(pos.getX(), pos.getY(), 30, 30);
}
}
class BlackChess extends Chess {
@Override
public Color getColor() {
return Color.BLACK;
}
}
class WiteChess extends Chess {
@Override
public Color getColor() {
return Color.WHITE;
}
}
public class Main extends MouseAdapter {
private final int x = 50;
private final int y = 50;
private final int w = 40; //小方格宽度和高度
private final int rw = 400; //棋盘宽度和高度
JFrame f;
JRadioButton wz, bz;
Graphics g;
JPanel CenterJP;
public static void main(String a[]) {
new Main();
}
Main(){
draw();
}
void draw() {
f = new JFrame("享元模式在五子棋游戏中的应用");
f.setBounds(100, 100, 500, 550);
f.setVisible(true);
f.setResizable(false);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel SouthJP = new JPanel();
f.add("South", SouthJP);
wz = new JRadioButton("白子");
bz = new JRadioButton("黑子", true);
CenterJP = new JPanel();
CenterJP.setLayout(null);
CenterJP.setSize(500, 500);
CenterJP.addMouseListener(this);
f.add("Center", CenterJP);
ButtonGroup group = new ButtonGroup();
group.add(wz);
group.add(bz);
SouthJP.add(wz);
SouthJP.add(bz);
try {
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
g = CenterJP.getGraphics();
g.setColor(Color.BLUE);
g.drawRect(x, y, rw, rw);
for (int i = 1; i < 10; i++) {
//绘制第i条竖直线
g.drawLine(x + (i * w), y, x + (i * w), y + rw);
//绘制第i条水平线
g.drawLine(x, y + (i * w), x + rw, y + (i * w));
}
}
@Override
public void mouseClicked(MouseEvent e) {
ChessFactory factory=ChessFactory.getInstance();
//棋子的位置就是鼠标点击的位置
Pos pos = new Pos(e.getX() - 15, e.getY() - 15);
Chess chess=null;
if (wz.isSelected()) {
chess=factory.getChese("w");
} else if (bz.isSelected()) {
chess=factory.getChese("b");
}
if(chess==null)return;
chess.display(pos,g);
}
}
案例2:java中的包装类和字符串
特点
1.当对象状态大部分可以外部化时,可以使用享元模式
2.减少了外部对象的创建,节省内存
3.维护享元池需要耗费一定系统资源,只有在重复使用对象是,采用该模式
7.代理模式
静态代理
角色
1.抽象主题:代理主题和真实主题的公共接口
2.代理主题:增加对真实主题方法的约束
3.真实主题
案例:模拟登陆
class Validator {
public boolean validate(String userId) {
System.out.println("验证UserID" + userId);
return true;
}
}
class Logger {
public void log(String userId) {
System.out.println("记录日志" + userId);
}
}
//被代理对象的方法
interface Dao {
public boolean login(String userId);
}
class UserDao implements Dao {
@Override
public boolean login(String userId) {
System.out.println("用户" + userId + "登录成功");
return true;
}
}
//代理对象
class DaoProxy implements Dao {
private Dao dao;
public DaoProxy(Dao dao) {
this.dao = dao;
}
@Override
public boolean login(String userId) {
Validator validator = new Validator();
if (!validator.validate(userId)) return false;
//在登陆前后进行验证和写日志的操作
boolean state = dao.login(userId);
Logger logger = new Logger();
logger.log(userId);
return state;
}
}
public class Main {
public static void main(String args[]) {
Dao dao = new DaoProxy(new UserDao());
dao.login("u1");
}
}
动态代理
角色
1.代理工厂
2.真实主题
3.抽象主题
通过java的proxy实现
//抽象主题
interface Dao{
String find(int id);
boolean insert(int id,String msg);
}
//真实主题
class UserDao implements Dao
{
@Override
public String find(int id) {
return "name: ljn";
}
@Override
public boolean insert(int id, String msg) {
System.out.printf("执行inrset操作%d %s",id,msg);
return true;
}
}
//代理工厂,返回的代理对象实现了Dao接口
class ProxyFactory{
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//返回代理对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(target.getClass().getClassLoader()
, target.getClass().getInterfaces(), new InvocationHandler() {
//invoke:钩子函数,描述了代理细节
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("账号验证");
//对于为-1的参数,修改为1
for (int i = 0; i <args.length ; i++) {
if(args[i] instanceof Integer)
{
if((Integer)args[i]==-1)
{
args[i]=0;
}
}
}
//让真实对象执行被代理方法
Object res= method.invoke(target,args);
System.out.println(res);
System.out.println("写入日志文件");
return res;
}
});
}
}
public class Main {
public static void main(String a[]){
ProxyFactory pf=new ProxyFactory(new UserDao());
Dao proxyDao = (Dao)pf.getProxyInstance();
System.out.println(proxyDao.insert(-1,"insert name"));
}
}
通过Cglib框架实现
class UserDao {
String get(int id, String password, int age) {
return String.valueOf(id) + " " + password +
" " + String.valueOf(age);
}
}
class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getInstance() {
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("校验账户");
Object res = method.invoke(target, objects);
return res;
}
}
public class Main {
public static void main(String args[]){
ProxyFactory pf=new ProxyFactory(new UserDao());
UserDao udaoproxy = (UserDao)pf.getInstance();
String res = udaoproxy.get(1, "this is my", 12);
System.out.println(res);
}
}
优点
1.解耦,使用户针对抽象主题编程,增加可扩展性
2.远程代理:将资源消耗大的操作移动到别的电脑上
3.虚拟代理:通过一个资源消耗低的对象代表资源消耗高的对象
4.缓存代理
5.保护代理:控制对对象的访问权限
缺点
1.增加了代理对象,影响性能
2.需要额外的工作
8.模板方法模式
角色
1.抽象类
1.抽象方法:必须由子类实现
2.具体方法:父类已经实现了
3.钩子方法:父类作了空实现,子类可以加以扩展
2.具体类
简介
模板方法定义骨架,子类型对骨架作具体实现和扩充
abstract class DataViewer{
public abstract void getData();
public void convertData(){
System.out.println("将数据转换为默认格式");
}
public abstract void display();
//判断是否转化
//钩子函数,默认设置为true
public boolean isNotFormat(){
return true;
}
//模板方法
public void process(){
getData();
if(isNotFormat())convertData();
display();
}
}
class XMLDataViewer extends DataViewer{
@Override
public void getData() {
System.out.println("从xml中获取数据");
}
@Override
public void display() {
System.out.println("显示xml格式数据");
}
@Override
public boolean isNotFormat(){
System.out.println("判断当前格式是否符合");
return false;
}
}
public class Main {
public static void main(String[] args){
DataViewer dv=new XMLDataViewer();
dv.process();
}
}
安卓里的应用
//模板方法实现生命周期管理
public abstract class IBaseActivity extends AppCompatActivity {
private SystemBarTintManager tintManager;
private int systemBarColor = R.color.colorPrimaryDark;//默认的状态栏颜色
protected final EventBus mEventBus = EventBus.getDefault();//事件总线
//模板方法:确立所有基本方法的调用时序和逻辑
@Override
protected final void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getArgs();
setContentView(initLayout());
initWindow(systemBarColor);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN | WindowManager.LayoutParams
.SOFT_INPUT_STATE_HIDDEN);//解决Andriod软键盘出现把原来的布局给顶上去的方法
ButterKnife.bind(this);
initView();
requestData();
}
/**
* 基本方法 用于返回布局ID
*/
public abstract int initLayout();
/**
* 基本方法 初始化View
*/
protected abstract void initView();
/**
* 基本方法,获取数据,执行耗时操作
*/
protected abstract void requestData();
/**
* 提供给子类动态设置状态栏颜色
*/
protected void setSystemBarColor(int colorId) {
initWindow(colorId);
}
//...省略一体化状态栏处理
/**
* 该方法在onCreate中执行,用于获取Fragment的参数传递
* 子类可按情况自行选择复写
*/
protected void getArgs() {
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mEventBus.isRegistered(this)) mEventBus.unregister(this);
ButterKnife.unbind(this);//取消注入
}
}
//使用,重写了父类的基本方法,通过钩子函数扩充
public class TestActivity extends IBaseActivity {
@Override
public int initLayout() {
return 0;
}
@Override
protected void initView() {
}
@Override
protected void requestData() {
}
}
优点
1.父类只需要在模板方法里定义基本方法的调用顺序逻辑,子类就能通过实现基本方法来扩充算法细节
2.实现反向控制,子类通过覆盖钩子函数来决定模板方法的某一步是否需要执行
3.符合开闭原则
缺点
如果父类中基本方法太多会产生大量的子类
9.命令者模式
角色
1.Invoker:命令发起者
2.Reciever:命令接受者
3.Command:抽象命令
4.具体命令:将接受者和一个动作绑定
命令发起者无需和命令接受者直接交互,只需要发布命令,当命令执行时,委托接受者完成相应的操作
设计修改按钮功能的系统
//Invoker
class Button{
private Cmd cmd;
public void setCmd(Cmd cmd) {
this.cmd = cmd;
}
public Button(Cmd cmd) {
this.cmd = cmd;
}
public void click(){
System.out.println("单机按钮");
cmd.execute();
}
}
//Command
abstract class Cmd{
public abstract void execute();
}
//Reciever
class SystemExitsCLass{
void exit(){
System.out.println("系统退出");
}
}
class ExitCmd extends Cmd{
SystemExitsCLass seObj=new SystemExitsCLass();
@Override
public void execute() {
seObj.exit();
}
}
//Reciever
class Helper{
void help(){
System.out.println("跳转到帮助页面");
}
}
class HelpCmd extends Cmd{
Helper helper=new Helper();
@Override
public void execute() {
helper.help();
}
}
public class Main {
public static void main(String args[]) {
Cmd cmd=new HelpCmd();
Button b=new Button(cmd);
b.click();
//更换按钮的功能
cmd=new ExitCmd();
b.setCmd(cmd);
b.click();
}
}
适用环境
-
将请求接受者和调用者解耦
- 系统需要在不同的时间点指定请求,维护请求队列,执行请求。
- 系统需要支持undo redo操作
- 支持一组命令操作形成的宏命令
缺点
引入大量的命令类,不易维护
10.访问者模式
角色
- Visitor(抽象访问者):针对每一种类型的元素定义访问方式
- Element(抽象元素):accept(Visitor v) 用于接收访问
- ConcreteElement(具体元素):在accept(Visitor v)调用访问者的访问方法
- ElementList(元素集合)
员工管理系统
interface Employee {
void accept(Visitor hanlder);
}
abstract class Visitor {
public abstract void vist(FulltimeEmployee employee);
public abstract void vist(ParttimeEmployee employee);
// public abstract void vist(BossEmployee employee);
// public abstract void vist(SupermanEmployee employee);
}
class EmployeeList {
private List<Employee> employeeList = new ArrayList<>();
public void add(Employee e) {
employeeList.add(e);
}
public void remove(Employee e) {
employeeList.remove(e);
}
public void accept(Visitor handler){
for(Employee e:employeeList)e.accept(handler);
}
}
class FulltimeEmployee implements Employee {
private String name;
private double weeklyWage;
private int workTime;
public FulltimeEmployee(String name, double weeklyWage, int workTime) {
this.name = name;
this.weeklyWage = weeklyWage;
this.workTime = workTime;
}
@Override
public void accept(Visitor hanlder) {
hanlder.vist(this);
}
getter() setter()
}
class ParttimeEmployee implements Employee {
String name;
double hourlyWage;
int workTime;
public ParttimeEmployee(String name, double hourlyWage, int workTime) {
this.name = name;
this.hourlyWage = hourlyWage;
this.workTime = workTime;
}
@Override
public void accept(Visitor hanlder) {
hanlder.vist(this);
}
gsetter()
};
//按部门计算工资就是访问者
class FADepartment extends Visitor {
@Override
public void vist(FulltimeEmployee employee) {
int workTime = employee.getWorkTime();
double weekWage = employee.getWeeklyWage();
if (workTime > 40) weekWage += (workTime - 40) * 100;
else if (workTime < 40) {
weekWage -= (workTime - 40) * 80;
if (weekWage <= 0) weekWage = 0;
}
System.out.printf("正式员工%s的工作时间:%d 工资为%f\n",
employee.getName(), workTime, weekWage);
}
@Override
public void vist(ParttimeEmployee employee) {
System.out.printf("临时员工%s的工作时间:%d 工资为%f\n", employee.getName(),
employee.getWorkTime(), employee.getHourlyWage());
}
}
class HRDepartment extends Visitor {
@Override
public void vist(FulltimeEmployee employee) {
int workTime = employee.getWorkTime();
double weekWage = employee.getWeeklyWage();
System.out.printf("正式员工%s的实际工作时间:%d ",
workTime);
if (workTime > 40)
System.out.printf("正式员工%s的加班时间:%d ",
workTime - 40);
else if (workTime < 40) {
System.out.printf("正式员工%s的迟到时间:%d \n",
workTime - 40);
}
}
@Override
public void vist(ParttimeEmployee employee) {
System.out.printf("临时员工%s的实际工作时间:%d \n",
employee.getName(), employee.getWorkTime());
}
}
public class Main {
public static void main(String args[]){
EmployeeList empList=new EmployeeList();
Employee e1=new ParttimeEmployee("p1",2,3);
Employee e2=new ParttimeEmployee("p2",3,4);
Employee e3=new FulltimeEmployee("p3",4,5);
Employee e4=new FulltimeEmployee("p4",5,5);
empList.add(e1);
empList.add(e2);
empList.add(e3);
empList.add(e4);
//调用者只需要依赖Visitor和empList
Visitor vs=new FADepartment();
empList.accept(vs);
}
}
使用环境:对集合里的不同种类的元素定义不同的访问方式,如XML解析
优点:
1.便于扩充新的访问操作,增加访问操作符合OCP
2.相同的对象可以供不同的访问者访问
缺点:
1.增加新的元素种类违背OCP,没加新元素,都得怎讲新的抽象操作
2.元素对象供访问者访问时需要暴露内部操作
11.责任链模式
角色
1.Handler:抽象责任链节点
2.具体处理者
UI事件冒泡
abstract class Handler{
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handle(String event);
}
class Button extends Handler{
int id;
public Button(int id) {
this.id = id;
}
@Override
public void handle(String event) {
System.out.printf("<button id=%d> 处理事件\n 事件=%s",id,event);
event+="btn"+String.valueOf(id);
nextHandler.handle(event);
}
}
class Block extends Handler{
int id;
public Block(int id) {
this.id = id;
}
@Override
public void handle(String event) {
System.out.printf("<div id=%d> 处理事件\n 事件=%s",id,event);
event+="block"+String.valueOf(id);
nextHandler.handle(event);
}
}
class Window extends Handler{
int id;
public Window(int id) {
this.id = id;
}
@Override
public void handle(String event) {
System.out.printf("<window id=%d> 处理事件\n 事件=%s",id,event);
event+="window"+String.valueOf(id);
}
}
public class Main {
public static void main(String a[]){
Handler w1=new Window(1);
Handler div1=new Block(2);
Handler div2=new Block(3);
Handler btn=new Button(4);
btn.setNextHandler(div1);
div1.setNextHandler(div2);
div2.setNextHandler(w1);
btn.handle(" click ");
}
}
应用场景:Filter过滤器,异常处理模块,事件冒泡
优点:
1. 用户无需关心是谁处理了请求
2. 动态改变节点的职责
3. 增加处理者无需改代码,符合OCP
缺点:
1. 过长的责任链引起性能损耗
2. 调用不当,会触发循环调用
12.中介者模式
角色
1. Mediator:定义和同事通信的接口
2. Concrete Mediator :维护了所有同事的引用
3. Colleague:维护对Mediator的引用
4. Concrete Colleague
案例UI组件联动,每个UI组件会影响到其他的UI组件
抽象层
abstract class Mediator {
public abstract void componentUpdate(MComponent c);
}
abstract class MComponent {
public final Dimension defalutDimension = new Dimension(400, 400);
final Font charecterFont = new Font("宋体", Font.BOLD, 36);
protected Mediator mediator;
//将Mediator和MComponent绑定
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public void changed() {
mediator.componentUpdate(this);
}
}
具体的Mediator
如果想改变对同事的操作处理,或者增加新的同事,可以用继承防止修改
class ConcreteMediator extends Mediator {
//为了代码的可读性,这里省略了private和访问器
MList list;
MBtn btn;
MText txt;
//输入同事,并且建立和同事的绑定
public ConcreteMediator(MList list, MBtn btn, MText txt) {
this.list = list;
this.btn = btn;
this.txt = txt;
list.setMediator(this);
btn.setMediator(this);
txt.setMediator(this);
}
//同事之间的交互细节
@Override
public void componentUpdate(MComponent c) {
if (c == list) {
txt.setText(list.getSelected());
} else if (c == btn) {
list.add("btn msg");
txt.setText("btn msg");
} else if (c == txt) {
list.add(txt.getTextField().getText());
}
}
}
组件类,具体同事的实现
每一种UI组件在被点击的时候通知Mediator
class MText extends MComponent {
//为了可读性,省略了访问器
JTextField textField;
public void setText(String s) {
textField.setText(s);
}
public MText(String text, JPanel jp) {
textField = new JTextField(50);
textField.setText(text);
textField.addActionListener((e) -> {
changed();
});
textField.setFont(charecterFont);
textField.setSize(defalutDimension);
jp.add(textField);
}
}
class MBtn extends MComponent {
JButton jb;
MBtn(String text, JPanel jp) {
jb = new JButton(text);
jb.setSize(defalutDimension);
jb.setFont(charecterFont);
jp.add(jb);
jb.addActionListener((e) -> {
changed();
});
}
}
class MList extends MComponent {
JList list;
List<String> data;
MList(List<String> arr, JPanel jp) {
data = arr;
list = new JList(data.toArray());
list.setFont(charecterFont);
list.setSize(defalutDimension);
list.addListSelectionListener((e) -> {
changed();
});
jp.add(list);
}
void add(String s) {
data.add(s);
list.setListData(data.toArray());
}
String getSelected() {
return (String) list.getSelectedValue();
}
}
public class Main extends JFrame {
Main() {
super();
setTitle(" GUI 程序"); //设置显示窗口标题
setSize(800, 800); //设置窗口显示尺寸
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //置窗口是否可以关闭
JPanel jp = new JPanel();
add(jp);
place(jp);
setVisible(true);
}
void place(JPanel panel) {
panel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
//创建同事
MText mLable = new MText("空", panel);
MBtn btn = new MBtn("b1", panel);
List<String> dataList = new ArrayList<>();
dataList.add("aa");
dataList.add("bb");
MList mList = new MList(dataList, panel);
//创建Mediator
Mediator mediator=new ConcreteMediator(mList,btn,mLable);
panel.setBounds(300, 200, 400, 200);
panel.show();
}
public static void main(String[] args) {
new Main();
}
}
优点:
- 简化了大量对象的操作,用中介和同事的操作代替了同事直接的交互,将多对多的关系转化成一对多的关系
- 将同事和同事直接的关系解耦,当同事直接的交互关系改变时,引入新的中介者即可
缺点
中介者中componentUpdate()方法包含同事之间的交互细节难以维护
13.备忘录模式
角色
- Originator(原发器):需要保存内部状态的类
- Memento(备忘录):由Originator生成
- Caretaker(负责人):负责管理Memento
//需要备份的类
class Originator{
String state;
public Originator(String state) {
this.state = state;
}
public Memento createMemento(){
return new Memento(state);
}
public void undo(Memento memento){
this.state=memento.state;
}
}
class Memento{
String state;
public Memento(String state) {
this.state = state;
}
}
class Caretaker{
Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
public class Main {
public static void main(String a[]){
Originator o1=new Originator("state1");
System.out.println(o1.state);
//创建管理员
Caretaker ck=new Caretaker();
//管理备份
ck.setMemento(o1.createMemento());
o1.state="s2";
System.out.println(o1.state);
//回滚
o1.undo(ck.getMemento());
System.out.println(o1.state);
}
}
优点:用备忘录对象保存原始对象,备忘录对象不会被其他对象改动
缺点:如果原对象成员太多,就会占用大量的空间
14.状态模式
角色:
- Context:维护状态
- State :抽象状态
- Concrete State
案例 银行管理系统
抽象层
abstract class State {
//持有一个上下文对象,方便进行状态转换
protected Account account;
protected abstract void deposite(double amount);
protected abstract void withdraw(double amount);
protected abstract void computeIntereste();
//检查当前状态,并进行状态转换
protected abstract void stateCheck();
public State(Account account) {
this.account = account;
}
}
Context
class Account{
private State state;
private String user;
private double balance;
public void computeIntereste(){
state.computeIntereste();
}
public void deposite(double v){
System.out.printf("用户%s 存款%3f\n",user,v);
state.deposite(v);//委托状态进行操作
System.out.printf("余额%f\n",balance);
System.out.printf("状态为%s\n",state.getClass().getName());
}
public void withdraw(double v){
System.out.printf("用户%s 取款%3f\n",user,v);
state.withdraw(v);
System.out.printf("余额%f\n",balance);
System.out.printf("状态为%s\n",state.getClass().getName());
}
}
Concrete State
在不同具体状态下,执行业务和状态转移的细节都不同
class OverDraft extends State{
public OverDraft(Account account) {
super(account);
}
@Override
protected void deposite(double amount) {
account.setBalance(account.getBalance()+amount);
stateCheck();
}
@Override
protected void withdraw(double amount) {
System.out.println("理性消费");
account.setBalance(account.getBalance()-amount);
stateCheck();
}
@Override
protected void computeIntereste() {
System.out.println("计算利息");
}
@Override
protected void stateCheck() {
double b=account.getBalance();
if(b>0)account.setState(new Normal(account));
else if (b==-2000)
account.setState(new Restricted(account));
else if(b<-2000)
System.out.println("操作失败");
}
}
class Restricted extends State{
public Restricted(Account account) {
super(account);
}
@Override
protected void deposite(double amount) {
account.setBalance(account.getBalance()+amount);
stateCheck();
}
@Override
protected void withdraw(double amount) {
System.out.println("当前状态没法取钱");
}
@Override
protected void computeIntereste() {
System.out.println("计算利息");
}
@Override
protected void stateCheck() {
double b=account.getBalance();
if(b>0)account.setState(new Normal(account));
else if(b>-2000)
account.setState(new OverDraft(account));
}
}
class Normal extends State{
public Normal(Account account) {
super(account);
}
@Override
protected void deposite(double amount) {
account.setBalance(account.getBalance()+amount);
stateCheck();
}
@Override
protected void withdraw(double amount) {
account.setBalance(account.getBalance()-amount);
stateCheck();
}
@Override
protected void computeIntereste() {
System.out.println("无需支付利息");
}
@Override
protected void stateCheck() {
double b=account.getBalance();
if(b>-2000&&b<0)
account.setState(new OverDraft(account));
else if(b==-2000)
account.setState(new Restricted(account));
else if(b<-2000)
System.out.println("操作失败");
}
}
public class Main {
public static void main(String a[]){
Account ac=new Account("1",20);
ac.setState(new Normal(ac));
//创建Contex,并设置初始状态
ac.deposite(80);
ac.computeIntereste();
ac.withdraw(1100);
ac.computeIntereste();
ac.withdraw(1000);
ac.computeIntereste();
ac.withdraw(1000);
}
}
/*
用户1 存款80.000000
余额100.000000
状态为state.demo.Normal
无需支付利息
用户1 取款1100.000000
余额-1000.000000
状态为state.demo.OverDraft
计算利息
用户1 取款1000.000000
理性消费
余额-2000.000000
状态为state.demo.Restricted
计算利息
用户1 取款1000.000000
当前状态没法取钱
余额-2000.000000
状态为state.demo.Restricted
*/