java 生成器_Java设计模式:生成器模式

问题的提出:

有些类很容易创建对象,直接调用其构造方法,例如Student student = new Student(“1001”,”zhang”,21); 之所以容易创建,因为其类成员都是基本数据类型或者封装类,或者字符串。但是如果对象的类成员还是对象,那么创建这个对象还需要产生该对象成员的具体对象。

public classUnit1 {

}

public classQuestionProduct {

Unit1 u1;

Unit2 u2;

Unit3 u3;public voidcreateUnit1(){

u1= newUnit1();

}public voidcreateUnit2(){

u2= newUnit2();

}public voidcreateUnit3(){

u3= newUnit3();

}public voidcomposite(){

}public static voidmain(String[] args) {

QuestionProduct p= newQuestionProduct();

p.createUnit1();

p.createUnit2();

p.createUnit3();

p.composite();

}

}

Unit123为各java对象,在main方法可以知道,只有当运行完p.composite()方法后,Product才真正的创建起来,问题来了,如果有两类Product对象,又或许有很多类成员。又或者随着Product产品种类的增加和减少,必须修改已有的源代码。于是为了解决这类问题,生成器模式应运而生!

生成器模式的主要思路是:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。简单来说,不在同一类里面创建该类的类成员,而是把类成员的创建交给另一个类,该类就叫做生成器!

public interfaceIBuild {publicProduct create();

}

public class BuildProduct implementsIBuild {

Product p= newProduct();public voidcreateUnit1(){//创建u1

}public voidcreateUnit2(){//创建u2

}public voidcreateUnit3(){//创建u3

}publicProduct composite(){//关联Unit1,Unit2,Unit3

returnp;

}publicProduct create(){

createUnit1();

createUnit2();

createUnit3();returncomposite();

}

}

通过上面的代码可以知道,如果需求分析发生变化,只需要增加或者删除相应的生成器类BuildProduct即可,并不需要修改已有的类代码。

在这基础上,再定义一个调度类,是对生成器接口的IBuild的封装。

public classDirector {privateIBuild iBuild;publicDirector(IBuild iBuild){this.iBuild =iBuild;

}publicProduct build(){//System.out.println("test");

iBuild.createUnit1();

iBuild.createUnit2();

iBuild.createUnit3();returniBuild.composite();

}public static voidmain(String[] args) {

IBuild iBuild= newBuildProduct();

Director director= newDirector(iBuild);

Product p=director.build();

}

}

这样就构成生成器模式的一般模式了!一般分为以下三个步骤

1)定义产品类

2)定义n个生成器Build类

3)定义一个统一调度类Director类

ce9403bd2fd47465218bfbc01d09d16f.png

对于Director的理解:与常规的接口相比,生成器接口IBuild是特殊的,它是一个流程控制接口。该接口中定义的方法必须依照某种顺序执行,一个都不能少。因此在程序中一个要体现出“流程”这一特点。而Director类的作用就是对“流程”的封装类,其中的build方法决定了具体的流程控制过程。

对于上面的生成器模式,假如要生成两种Product产品,一种需要三种过程,一种需要四种过程,那么用上面的生成器模式(Model1)就不行了,因为它要求创建产品的过程必须相同(Interface IBuild定义好了创建的过程)。于是引起下面Model2的设计。

30ab56896b7add3d49e8d70467f633fd.png

Model2:IBuild接口仅仅定义多态create()方法

public interfaceIBuild {publicProduct create();

}

而在具体生成器类重写多态create()方法,并调用多个个非多态方法,最终返回Product对象。

public class BuildProduct implementsIBuild {

Product p= newProduct();public voidcreateUnit1(){//创建u1

}public voidcreateUnit2(){//创建u2

}public voidcreateUnit3(){//创建u3

}publicProduct composite(){//关联Unit1,Unit2,Unit3

returnp;

}publicProduct create(){

createUnit1();

createUnit2();

createUnit3();returncomposite();

}

}

Director类

public classDirector {privateIBuild iBuild;publicDirector(IBuild iBuild){this.iBuild =iBuild;

}publicProduct build(){returniBuild.create();

}

}

对代码进行仔细分析可以发现,具体生成器多态的create()方法中包含了创建Product对象的全过程,Director类中的方法就显得重复了。在这种设计中其实是可以省略Director类的,这就说明了在生成器模式中,抽象生成器和具体生成器是必须的。

而指挥类需要在实际问题中认真考虑,加以取舍!进一步思考,可以把IBuild定义成泛型接口,不仅仅是Product产品,也可以是其他需要生成器魔术的产品都可以从这接口派生。

除了以上两种实现方式,还有第三种生成器功能的设计模式。

Model3:利用Product派生方法,可以实现类似生成器功能

3d630bf4a3dbf56d1e013618d1efbdff.png

具体代码如下

1.Product类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public abstract classProduct {

Unit1 u1;

Unit2 u2;

Unit3 u3;abstract void createUnit1(); //表明子类要创建Unit1,2,3,并组合它

abstract voidcreateUnit2();abstract voidcreateUnit3();abstract voidcomposite();

}

View Code

2.生成器BuildProduct类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public class BuildProduct extendsProduct {voidcreateUnit1(){}voidcreateUnit2(){}voidcreateUnit3(){}voidcomposite(){}

}

View Code

3.指挥者类Director

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

public classDirector {

Product p;publicDirector(Product p){this.p =p;

}voidbuild(){

p.createUnit1();

p.createUnit2();

p.createUnit3();

p.composite();

}

}

View Code

总而言之,对于生成器模式创建复制对象而言,主要的原则还是对象构建过程与表示相分离。这是一个总的思想,实现具体形式不是一成不变,大可以设计自己专属的生成器模式框架。重要的是思想,而不是实现形式!

最后再说说生成器模式的应用场景,其中一个比较重要的作用就是解决同流程,异界面的手段之一。

例如在登录下常常都会分不同的角色,比如教务系统登录区分教师和学生。一般的应用也分为管理员以及普通用户。不同的角色登录后或显示不同的页面。下面就教学管理系统这个例子简单说明。

253fd6d7bc6463eb9b880ee517f1b0d8.png        

d3e1f5870ed922675dcba72ce0e6e38f.png

7f2233253738ca78add4f5fe414f68c8.png

学生的具体信息在student表中,教师的具体信息在teacher表中。一个常用的功能是:管理员为学生和教师在login表中分配了用户名和账号,同时在student和teacher表中建立关键字user的记录。但是其他具体信息如姓名年龄等是空的。

因此需要学生或者教师在登录后首先完善个人信息。下面正是利用生成器模式设计“个人信息完善”的基础代码。

Mysql 表的简单设计

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

create tablestudent (User varchar(20),

namevarchar(20),

ageint,

majorvarchar(20),

departvarchar(20)

)insert student values('1001','张同学',21,'English','Computer');insert student (user) values('1002');

View Code

1)界面抽象生成器UIBuilder

packageBuildModel.Example;import javax.swing.*;/*** Created by lenovo on 2017/4/18.*/

public abstract classUIBuilder {protected JPanel panel = newJPanel();abstract public void addUI(); //形成界面

abstract public void registerMsg(); //注册消息

abstract public void initialData(String user); //初始化界面数据

public JPanel getPanel(){ //返回界面面板对象

returnpanel;

}

}

2)具体学生界面生成器类StudentBuilder

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packageBuildModel.Example;import javax.swing.*;import java.awt.*;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.util.Vector;/*** Created by lenovo on 2017/4/18.*/

public class StudentBuilder extends UIBuilder implementsActionListener {

String user;

JTextField studName= new JTextField(10); //姓名

JTextField studAge = new JTextField(10); //年龄

JTextField studMajor = new JTextField(10); //专业

JTextField studDepart = new JTextField(10); //学院

JButton updateBtn = new JButton("更新"); //该按钮需注册时间

public voidaddUI(){

JPanel center= newJPanel();

JPanel south= newJPanel();

Box b= Box.createVerticalBox(); //第1列垂直box对象b

b.add(new JLabel("姓名")); b.add(Box.createVerticalStrut(8));

b.add(new JLabel("年龄")); b.add(Box.createVerticalStrut(8));

b.add(new JLabel("专业")); b.add(Box.createVerticalStrut(8));

b.add(new JLabel("学院")); b.add(Box.createVerticalStrut(8));

Box b2= Box.createVerticalBox(); //第2列垂直Box对象b2

b2.add(studName); b2.add(Box.createVerticalStrut(8));

b2.add(studAge); b2.add(Box.createVerticalStrut(8));

b2.add(studMajor); b2.add(Box.createVerticalStrut(8));

b2.add(studDepart); b2.add(Box.createVerticalStrut(8));

center.add(b);

center.add(b2);//center面板 = b + b2

south.add(updateBtn); //south面板 = updateBtn

panel.setLayout(newBorderLayout());

panel.add(center,BorderLayout.CENTER);

panel.add(south,BorderLayout.SOUTH);

}public voidregisterMsg(){

updateBtn.addActionListener(this);

}public void initialData(String user1){ //界面数据显示初始化

this.user =user1;

String SQL= "select name,age,major,depart from student where user = '"

+ user + "'";

DbProc dbobj= new DbProc(); //数据库操作类

try{

dbobj.connect();

Vector l=(Vector) dbobj.executeQuery(SQL);

Vector v= (Vector)l.get(0);

studName.setText((String)v.get(0));

studAge.setText((String)v.get(1));

studMajor.setText((String)v.get(2));

studDepart.setText((String)v.get(3));

dbobj.close();

}catch(Exception ex){

ex.printStackTrace();

}

}public void actionPerformed(ActionEvent arg0){ //获得界面数据+更新数据库

String name =studName.getText();

String major=studMajor.getText();

String age=studAge.getText();

String depart=studDepart.getText();

String strSQL= "update student set name='" + name + "',age=" +age+ ",major='" + major + "',depart='" + depart + "'" +

"where user='" + user + "'";try{

DbProc dbProc= newDbProc();

dbProc.connect();

dbProc.executeUpdate(strSQL);

dbProc.close();

}catch(Exception ex){

ex.printStackTrace();

}

}

}

View Code

3)DbProc数据库自定义封装类(注意测试时候strPwd要加上自己本地mysql的账户密码)

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packageBuildModel.Example;import java.sql.*;importjava.util.List;importjava.util.Vector;/*** Created by lenovo on 2017/4/18.*/

public classDbProc {private String strDriver = "com.mysql.jdbc.Driver";private String strDb = "jdbc:mysql://localhost:3306/buildModel";private String strUser = "root";private String strPwd = ""; //注意测试时候strPwd要加上自己本地mysql的账户密码

privateConnection conn;public Connection connect() throwsException{

Class.forName(strDriver);

conn=DriverManager.getConnection(strDb,strUser,strPwd);returnconn;

}public int executeUpdate(String strSQL) throwsException{

Statement stm=conn.createStatement();int n =stm.executeUpdate(strSQL);

stm.close();returnn;

}public List executeQuery(String strSQL) throwsException{

List l= newVector();

Statement stm=conn.createStatement();

ResultSet rst=stm.executeQuery(strSQL);

ResultSetMetaData rsmd=rst.getMetaData();while(rst.next()){

Vector unit= newVector();for(int i=1;i<=rsmd.getColumnCount();i++){

unit.add(rst.getString(i));

}

l.add(unit);

}returnl;

}public void close() throwsException{

conn.close();

}

}

View Code

4)具体教师界面生成器TeacherBuilder(类似,这里就不写了)

5)流程指挥类Director

packageBuildModel.Example;import javax.swing.*;/*** Created by lenovo on 2017/4/18.*/

public classDirector {privateUIBuilder builder;publicDirector(UIBuilder builder){this.builder =builder;

}publicJPanel build(String user){

builder.addUI();//初始化界面

builder.registerMsg(); //登记消息

builder.initialData(user); //填充账号为user的初始界面显示数据

returnbuilder.getPanel();

}

}

6)测试类

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

packageBuildModel.Example;import javax.swing.*;/*** Created by lenovo on 2017/4/18.*/

public classMyTest {public static voidmain(String[] args) {

JFrame frm= newJFrame();

UIBuilder ub= new StudentBuilder(); //创建学生生成器

Director director = new Director(ub); //为学生生成器创建指挥者

JPanel panel = director.build("1001"); //指挥者建造张同学的更新界面

frm.add(panel);

frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frm.pack();

frm.setVisible(true);

}

}

View Code

当然这只是简单的测试代码,在实际应用中还要注意很多问题。

生成器模式就讲到这里,觉得文章写得不错大家多多支持,如果觉得有什么不足希望能在评论区提出!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值