设计模式总结

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();

    }
}

适用环境

  1. 将请求接受者和调用者解耦

    1. 系统需要在不同的时间点指定请求,维护请求队列,执行请求。
    2. 系统需要支持undo redo操作
    3. 支持一组命令操作形成的宏命令

缺点

引入大量的命令类,不易维护


10.访问者模式

角色

  1. Visitor(抽象访问者):针对每一种类型的元素定义访问方式
  2. Element(抽象元素):accept(Visitor v) 用于接收访问
  3. ConcreteElement(具体元素):在accept(Visitor v)调用访问者的访问方法
  4. 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();
    }
}

优点:

  1. 简化了大量对象的操作,用中介和同事的操作代替了同事直接的交互,将多对多的关系转化成一对多的关系
  2. 将同事和同事直接的关系解耦,当同事直接的交互关系改变时,引入新的中介者即可

缺点
中介者中componentUpdate()方法包含同事之间的交互细节难以维护






13.备忘录模式

角色

  1. Originator(原发器):需要保存内部状态的类
  2. Memento(备忘录):由Originator生成
  3. 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.状态模式

角色:

  1. Context:维护状态
  2. State :抽象状态
  3. 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


*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值