- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Java代码重用之功能与上下文重用由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
我几乎不需要讨论为什么重用代码是有利的。代码重用通常使得程序开发更加快速,并使得 bug 减少。一旦一段代码被封装和重用,那么只需要检查很少的一段代码即可确保程序的正确性。如果在整个应用程序中只需要在一个地方打开和关闭数据库连接,那么确保连接是否正常则容易的多。但我确信这些你已经都知道了.
有两种类型的重用代码,我称它们为重用类型:
第一种类型是功能重用,这是最常见的一种重用类型。这也是大多数开发人员掌握的一种。即重用一组后续指令来执行某种操作.
第二种类型是上下文重用,即不同功能或操作代码在相同上下文之间,将相同上下文封装为重用代码(这里的上下文指的是一系列相同的操作指令)。虽然它在控制反转中越来越受欢迎但它并不常见。而且,上下文重用并没有被明确的描述,因此它并没有像功能重用一样被系统的使用。我希望你看完这篇文章之后会有所改变.
功能重用 。
功能重用是最常见的重用类型。它是一组执行某种操作指令的重用。下面两个方法都是从数据库中读取数据:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
public
list readallusers(){
connection connection =
null
;
string sql =
"select * from users"
;
list users =
new
arraylist();
try
{
connection = openconnection();
preparedstatement statement = connection.preparestatement(sql);
resultset result = statement.executequery();
while
(result.next()){
// 重用代码
user user =
new
user();
user.setname (result.getstring(
"name"
));
user.setemail(result.getstring(
"email"
));
users.add(user);
// end 重用代码
}
result.close();
statement.close();
return
users;
}
catch
(sqlexception e){
//ignore for now
}
finally
{
//ignore for now
}
}
public
list readusersofstatus(string status){
connection connection =
null
;
string sql =
"select * from users where status = ?"
;
list users =
new
arraylist();
try
{
connection = openconnection();
preparedstatement statement = connection.preparestatement(sql);
statement.setstring(
1
, status);
resultset result = statement.executequery();
while
(result.next()){
// 重用代码
user user =
new
user();
user.setname (result.getstring(
"name"
));
user.setemail(result.getstring(
"email"
));
users.add(user);
// end 重用代码
}
result.close();
statement.close();
return
users;
}
catch
(sqlexception e){
//ignore for now
}
finally
{
//ignore for now
}
}
|
对于有经验的开发人员来说,可能很快就能发现可以重用的代码。上面代码中注释“重用代码”的地方是相同的,因此可以封装重用。这些是将用户记录读入用户实例的操作。可以将这些行代码封装到他们自己的方法中,例如:
1
2
3
4
5
6
7
8
|
// 将相同操作封装到 readuser 方法中
private
user readuser(resultset result)
throws
sqlexception {
user user =
new
user();
user.setname (result.getstring(
"name"
));
user.setemail(result.getstring(
"email"
));
users.add(user);
return
user;
}
|
现在,在上述两种方法中调用readuser()方法(下面示例只显示第一个方法):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public
list readallusers(){
connection connection =
null
;
string sql =
"select * from users"
;
list users =
new
arraylist();
try
{
connection = openconnection();
preparedstatement statement = connection.preparestatement(sql);
resultset result = statement.executequery();
while
(result.next()){
users.add(readuser(result))
}
result.close();
statement.close();
return
users;
}
catch
(sqlexception e){
//ignore for now
}
finally
{
//ignore for now
}
}
|
readuser()方法也可以在它自己的类中使用修饰符private隐藏.
以上就是关于功能重用的内容。功能重用是将一组执行特定操作的指令通过方法或类封装它们来达到重用的目的.
参数化操作 。
有时,你希望重用一组操作,但是这些操作在使用的任何地方都不完全相同。例如readallusers()和readusersofstatus()方法都是打开一个连接,准备一条语句,执行它,并循环访问结果集。唯一的区别是readusersofstatus()需要在preparedstatement上设置一个参数。我们可以将所有操作封装到一个readuserlist()方法。如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
private
list readuserlist(string sql, string[] parameters){
connection connection =
null
;
list users =
new
arraylist();
try
{
connection = openconnection();
preparedstatement statement = connection.preparestatement(sql);
for
(
int
i=
0
; i < parameters.length; i++){
statement.setstring(i, parameters[i]);
}
resultset result = statement.executequery();
while
(result.next()){
users.add(readuser(result))
}
result.close();
statement.close();
return
users;
}
catch
(sqlexception e){
//ignore for now
}
finally
{
//ignore for now
}
}
|
现在我们从readallusers()和readusersofstatus()调用readuserlist(...)方法,并给定不同的操作参数:
1
2
3
4
5
6
|
public
list readallusers(){
return
readuserlist(
"select * from users"
,
new
string[]{});
}
public
list readuserswithstatus(string status){
return
readuserlist(
"select * from users"
,
new
string[]{status});
}
|
我相信你可以找出其他更好的办法来实现重用功能,并将他们参数化使得更加好用.
上下文重用 。
上下文重用与功能重用略有不同。上下文重用是一系列指令的重用,各种不同的操作总是在这些指令之间进行。换句话说,重复使用各种不同行为之前和之后的语句。因此上下文重用通常会导致控制风格类的反转。上下文重用是重用异常处理,连接和事务生命周期管理,流迭代和关闭以及许多其他常见操作上下文的非常有效的方法.
这里有两个方法都是用 inputstream 做的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
public
void
printstream(inputstream inputstream)
throws
ioexception {
if
(inputstream ==
null
)
return
;
ioexception exception =
null
;
try
{
int
character = inputstream.read();
while
(character != -
1
){
system.out.print((
char
) character);
// 不同
character = inputstream.read();
}
}
finally
{
try
{
inputstream.close();
}
catch
(ioexception e){
if
(exception ==
null
)
throw
e;
}
}
}
public
string readstream(inputstream inputstream)
throws
ioexception {
stringbuffer buffer =
new
stringbuffer();
// 不同
if
(inputstream ==
null
)
return
;
ioexception exception =
null
;
try
{
int
character = inputstream.read();
while
(character != -
1
){
buffer.append((
char
) character);
// 不同
character = inputstream.read();
}
return
buffer.tostring();
// 不同
}
finally
{
try
{
inputstream.close();
}
catch
(ioexception e){
if
(exception ==
null
)
throw
e;
}
}
}
|
两种方法与流的操作是不同的。但围绕这些操作的上下文是相同的。上下文代码迭代并关闭 inputstream。上述代码中除了使用注释标记的不同之处外都是其上下文代码.
如上所示,上下文涉及到异常处理,并保证在迭代后正确关闭流。一次又一次的编写这样的错误处理和资源释放代码是很繁琐且容易出错的。错误处理和正确的连接处理在 jdbc 事务中更加复杂。编写一次代码并在任何地方重复使用显然会比较容易.
幸运的是,封装上下文的方法很简单。 创建一个上下文类,并将公共上下文放入其中。 在上下文的使用中,将不同的操作指令抽象到操作接口之中,然后将每个操作封装在实现该操作接口的类中(这里称之为操作类),只需要将该操作类的实例插入到上下文中即可。可以通过将操作类的实例作为参数传递给上下文对象的构造函数,或者通过将操作类的实例作为参数传递给上下文的具体执行方法来完成.
下面展示了如何将上述示例分隔为上下文和操作接口。streamprocessor(操作接口)作为参数传递给streamprocessorcontext的processstream()方法.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
// 流处理插件接口
public
interface
streamprocessor {
public
void
process(
int
input);
}
// 流处理上下文类
public
class
streamprocessorcontext{
// 将 streamprocessor 操作接口实例化并作为参数
public
void
processstream(inputstream inputstream, streamprocessor processor)
throws
ioexception {
if
(inputstream ==
null
)
return
;
ioexception exception =
null
;
try
{
int
character = inputstream.read();
while
(character != -
1
){
processor.process(character);
character = inputstream.read();
}
}
finally
{
try
{
inputstream.close();
}
catch
(ioexception e){
if
(exception ==
null
)
throw
e;
throw
exception;
}
}
}
}
|
现在可以像下面示例一样使用streamprocessorcontext类打印出流内容:
1
2
3
4
5
6
7
8
|
fileinputstream inputstream =
new
fileinputstream(
"myfile"
);
// 通过实现 streamprocessor 接口的匿名子类传递操作实例
new
streamprocessorcontext()
.processstream(inputstream,
new
streamprocessor(){
public
void
process(
int
input){
system.out.print((
char
) input);
}
});
|
或者像下面这样读取输入流内容并添加到一个字符序列中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public
class
streamtostringreader
implements
streamprocessor{
private
stringbuffer buffer =
new
stringbuffer();
public
stringbuffer getbuffer(){
return
this
.buffer;
}
public
void
process(
int
input){
this
.buffer.append((
char
) input);
}
}
fileinputstream inputstream =
new
fileinputstream(
"myfile"
);
streamtostringreader reader =
new
streamtostringreader();
new
streamprocessorcontext().processstream(inputstream, reader);
// do something with input from stream.
reader.getbuffer();
|
正如你所看到的,通过插入不同的streamprocessor接口实现来对流做任何操作。一旦streamprocessorcontext被完全实现,你将永远不会有关于未关闭流的困扰.
上下文重用非常强大,可以在流处理之外的许多其他环境中使用。一个明显的用例是正确处理数据库连接和事务(open - process - commit()/rollback() - close())。其他用例是 nio 通道处理和临界区中的线程同步(lock() - access shared resource - unlock())。它也能将api的已检查异常转换为未检查异常.
当你在自己的项目中查找适合上下文重用的代码时,请查找以下操作模式:
当你找到这样的模式时,前后的常规操作就可能实现上下文重用.
上下文作为模板方法 。
有时候你会希望在上下文中有多个插件点。如果上下文由许多较小的步骤组成,并且你希望上下文的每个步骤都可以自定义,则可以将上下文实现为模板方法。模板方法是一种 gof 设计模式。基本上,模板方法将算法或协议分成一系列步骤。一个模板方法通常作为一个单一的基类实现,并为算法或协议中的每一步提供一个方法。要自定义任何步骤,只需创建一个扩展模板方法基类的类,并重写要自定义的步骤的方法.
下面的示例是作为模板方法实现的 jdbccontext。子类可以重写连接的打开和关闭, 以提供自定义行为。必须始终重写processrecord(resultset result)方法, 因为它是抽象的。此方法提供不属于上下文的操作,在使用jdbccontext的不同情况下的操作都不相同。这个例子不是一个完美的jdbccontext。它仅用于演示在实现上下文时如何使用模板方法.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
public
abstract
class
jdbccontext {
datasource datasource =
null
;
// 无参数的构造函数可以用于子类不需要 datasource 来获取连接
public
jdbccontext() {
}
public
jdbccontext(datasource datasource){
this
.datasource = datasource;
}
protected
connection openconnection()
throws
sqlexception{
return
datasource.getconnection();
}
protected
void
closeconnection(connection connection)
throws
sqlexception{
connection.close();
}
// 必须始终重写 processrecord(resultset result) 方法
protected
abstract
processrecord(resultset result)
throws
sqlexception ;
public
void
execute(string sql, object[] parameters)
throws
sqlexception {
connection connection =
null
;
preparedstatement statement =
null
;
resultset result =
null
;
try
{
connection = openconnection();
statement = connection.preparestatement(sql);
for
(
int
i=
0
; i < parameters.length; i++){
statement.setobject(i, parameters[i]);
}
result = statement.executequery();
while
(result.next()){
processrecord(result);
}
}
finally
{
if
(result !=
null
){
try
{
result.close();
}
catch
(sqlexception e) {
/* ignore */
}
}
if(statement != null){
try{
statement.close();
}
catch(sqlexception e) {
/* ignore */
}
}
if
(connection !=
null
){
closeconnection(connection);
}
}
}
}
|
这是扩展 jdbccontext 以读取用户列表的子类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
class
readusers
extends
jdbccontext{
list users =
new
arraylist();
public
readusers(datasource datasource){
super
(datasource);
}
public
list getusers() {
return
this
.users;
}
protected
void
processrecord(resultset result){
user user =
new
user();
user.setname (result.getstring(
"name"
));
user.setemail(result.getstring(
"email"
));
users.add(user);
}
}
|
下面是如何使用 readusers 类:
1
2
3
|
readusers readusers =
new
readusers(datasource);
readusers.execute(
"select * from users"
,
new
object[
0
]);
list users = readusers.getusers();
|
如果readusers类需要从连接池获取连接并在使用后将其释放回该连接池,则可以通过重写openconnection()和closeconnection(connection connection)方法来插入该连接.
注意如何通过方法重写插入操作代码。jdbccontext的子类重写processrecord方法以提供特殊的记录处理。 在streamcontext示例中,操作代码封装在单独的对象中,并作为方法参数提供。实现操作接口streamprocessor的对象作为参数传递给streamcontext类的processstream(...)方法.
实施上下文时,你可以使用这两种技术。jdbccontext类可以将实现操作接口的connectionopener和connectioncloser对象作为参数传递给execute方法,或作为构造函数的参数。就我个人而言,我更喜欢使用单独的操作对象和操作接口,原因有两个。首先,它使得操作代码可以更容易单独进行单元测试;其次,它使得操作代码在多个上下文中可重用。当然,操作代码也可以在代码中的多个位置使用,但这只是一个优势。毕竟,在这里我们只是试图重用上下文,而不是重用操作.
结束语 。
现在你已经看到了两种不同的重用代码的方法。经典的功能重用和不太常见的上下文重用。希望上下文的重用会像功能重用一样普遍。上下文重用是一种非常有用的方法,可以从 api 的底层细节(例如jdbc,io 或 nio api等)中抽象出代码。特别是如果 api 包含需要管理的资源(打开和关闭,获得并返回等).
persistence/orm api、mr.persister 利用上下文重用来实现自动连接和事务生命周期管理。 这样用户将永远不必担心正确打开或关闭连接,或提交或回滚事务。mr.persister 提供了用户可以将他们的操作插入的上下文。 这些上下文负责打开,关闭,提交和回滚.
流行的 spring 框架包含大量的上下文重用。 例如 springs jdbc 抽象。 spring 开发人员将其使用上下文重用作为“控制反转”。 这不是 spring 框架使用的唯一一种控制反转类型。 spring 的核心特性是依赖注入 bean 工厂或“应用程序上下文”。 依赖注入是另一种控制反转.
以上所述是小编给大家介绍的java代码重用之功能与上下文重用,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我网站的支持! 。
原文链接:https://www.cnblogs.com/nwgdk/p/9008548.html 。
最后此篇关于Java代码重用之功能与上下文重用的文章就讲到这里了,如果你想了解更多关于Java代码重用之功能与上下文重用的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
出现以下错误 Network access for Distributed Transaction Manager (MSDTC) has been disabled. Please enable D
在调试应用程序时出现以下错误。 The CLR has been unable to transition from COM context 0x3b2d70 to COM context 0x3b2
在 GAE Go 中,为了记录,我们需要使用 appengine.NewContext(r) 创建一个新的上下文,它返回 context.Context。 如何使用此上下文在请求范围内设置/获取变量?
我想使用 Puppeteer 从放置在页面上 iframe 内的选择器中获取数据,该页面在与其父框架域不同的域上运行。因此,我不是任何域的所有者 - 无法使用 frame.postMessage。 试
我正在尝试获取可用的应用程序上下文并想切换到 webview 上下文,但 appium 仅获取 Navive App。 应用程序还启用了 WebView。 Appium 版本:1.10.1 Chrom
这个问题在这里已经有了答案: How to fix this nullOk error when using the flutter_svg package? (7 个回答) 7 个月前关闭。 当我尝
我观看了关于 Core Data 的 2016 WWDC 视频并查看了各种教程。我见过使用 Core Data Framework 创建对象以持久保存到 managedObjectContext 中的
这是代码 obj = { a: 'some value'; m: function(){ alert(this.a); } } obj.m(); 结果是'som
我正在尝试做类似的事情 $(".className").click(function() { $(this).(".anotherClass").css("z-index","1");
var User = { Name: "Some Name", Age: 26, Show: function() { alert("Age= "+this.Age)}; }; fun
我目前正在使用我见过的常见 Context 模式,它允许子组件通过传递修饰函数来更新父组件的状态(即 Provider)通过共享的 Context。 我遇到的问题是,修改函数只引用原始状态,不引用最新
有没有办法让 React Context类型安全与流类型? 例如: Button.contextTypes = { color: React.PropTypes.string }; 最佳答案 不幸
我想知道是否有一种方法可以为不同的功能使用不同的上下文类。 我希望有一个功能使用 MinkExtensions 进行浏览器测试,另一个功能使用和 HTTP 客户端(如 Guzzle)进行 API 测试
我有这个配置文件 apiVersion: v1 clusters: - cluster: server: [REDACTED] // IP of my cluster name: stag
我在实现非抢先式调度时遇到了用于初始化TCB的代码。 typedef struct TCB_t { struct TCB_t *next; struct TCB_t
我想将一个函数设置为数组中每个元素的属性,但使用不同的参数调用它。我想我会使用匿名函数来解决它: for ( var i = 0; i < object_count; i++ ) { obje
这个问题已经有答案了: How to access the correct `this` inside a callback (15 个回答) 已关闭 7 年前。 我正在做一些练习,但我在管道方法中丢
我正在尝试通过 Java 和 Android Studio 学习和制作 Android 应用程序。我对Java的了解程度是两年前几个小时的youtube学习和大学基础类(class)。不过我确实知道如
我在(这个)上遇到了问题。错误ImageView无法应用。我在 fragment 类中执行此代码。 ViewFlipper v_flipper; @Nullable @Override public
我想使用 openGL 的某些功能,但与渲染视觉内容无关。有没有办法在没有任何依赖性的情况下创建它(不是对 Windows,也不是某些包[SDL,SFML,GLUT])?只允许使用没有外部库的库,就像
我是一名优秀的程序员,十分优秀!