Java:可以访问超类字段和方法的策略模式?
Java: Strategy pattern with access to superclass' fields and methods?
我有一个抽象 class Parent
,其中包含抽象方法 foo()
和 bar()
以及其他非抽象方法和字段。我需要创建 4 个 subclasses(以及后来的更多)来涵盖 foo()
和 bar()
上不同变体的每个组合:fooA()
、fooB()
、barA()
、barB()
。这些变体需要访问 Parent
的其他字段和方法。
换句话说,如果 Java 支持多重继承,那么我会有这样的东西:
abstract class Parent{
abstract foo(){}
abstract bar(){}
//other fields and methods that will be accessed foo and bar are PROTECTED
}
abstract class FooA extends Parent{
@Override
foo(){ ... }
}
abstract class FooB extends Parent{
@Override
foo(){ ... }
}
abstract class BarA extends Parent{
@Override
bar(){ ... }
}
abstract class BarB extends Parent{
@Override
bar(){ ... }
}
class ChildAA extends FooA, BarA{
}
class ChildAB extends FooA, BarB{
}
class ChildBA extends FooB, BarA{
}
class ChildBB extends FooB, BarB{
}
我找到了两种解决方案,每一种都有效,但差不多。有没有更好的方法来实现这种行为?我的解决方案如下:
1)第一个解决方案:
abstract class Parent {
foo(){
/* behaves like fooA */
}
//other fields and methods that will be accessed foo and bar are PROTECTED
}
class ChildAA extends Parent{
barA(){ ... }
}
class ChildAB extends Parent{
barB(){ ... }
}
class ChildBA extends ChildAA{
@Override
foo(){ /* behaves like fooB */ }
|
class ChildBB extends ChildAB{
@Override
foo(){ /* behaves like fooB */ }
}
问题在于它复制了 fooB()
的代码以及只有 fooB()
需要的所有其他方法。当需要更多变化时,问题会呈指数级恶化。
2) 环顾四周后,我找到了设计模式 Strategy,它可以用来实现行为但很尴尬,因为变体需要访问 Parent
的字段和方法:
abstract class Parent{
Fooable fooable;
Barable barable;
foo(){ fooable.foo(); }
bar(){ barable.bar(); }
//other fields and methods that will be accessed foo and bar are PUBLIC
}
abstract class ImplementableParent{
Parent p;
ImplementableParent(Parent p) { this.p = p; }
}
interface Fooable{
foo();
}
class FooA extends ImplementableParent implements Fooable{
FooA(Parent p){ super(p); }
@Override
foo(){ /* behaves like FooA */ }
}
class FooB extends ImplementableParent implements Fooable{
FooB(Parent p){ super(p); }
@Override
foo(){ /* behaves like FooB */ }
}
interface Barable{
bar();
}
class BarA extends ImplementableParent implements Barable{
BarA(Parent p) { super(p); }
@Override
bar() { /* behaves like BarA */ }
}
class BarB extends ImplementableParent implements Barable{
BarB(Parent p) { super(p); }
@Override
bar() { /* behaves like BarB */ }
}
class ChildAA extends Parent{
fooable = new FooA(this);
barable = new BarA(this);
}
class ChildAB extends Parent{
fooable = new FooA(this);
barable = new BarB(this);
}
class ChildBA extends Parent{
fooable = new FooB(this);
barable = new BarA(this);
}
class ChildBB extends Parent{
fooable = new FooB(this);
barable = new BarB(this);
}
这消除了重复的变体,并且可以扩展以容纳更多变体。但是现在Parent
的字段和方法变成了public,整个感觉很绕。我还担心性能开销,因为 FooA
、FooB
、BarA
和 BarB
间接访问 Parent
方法,尽管我没有测试过。
是否有更好的方法来实现该行为?
However, now the fields and methods of Parent are public and the whole
thing feels very convoluted.
您的 Barable 和 Fooable 实现本身不保存上下文,因此它们必须使用上下文对象中的 public
方法(此处为 subclasses Parent
)查询和操作它。
但是只有 Parent
方法必须是 public,而不是它的字段。
例如,对于 Parent
和 FooA
实现来说,这将是一个公平的实现:
abstract class Parent{
private Fooable fooable; // internals
private Barable barable; // internals
private String sharedString; // internals
private Integer sharedInteger; // internals
// public access
public foo(){ fooable.foo(); }
public bar(){ barable.bar(); }
public String getSharedString(){
return sharedString;
}
public Integer getSharedInteger(){
return sharedInteger;
}
public String updateSharedData(String string, Integer integer){
// apply some logic and controls if required
this.string = string;
this.integer = integer;
}
}
class FooA extends ImplementableParent implements Fooable{
FooA(Parent p){
super(p);
}
@Override
foo(){
if (p.getSharedString().equals("...)){
// some logic
p.updateSharedData("new value", newIntegerValue);
}
}
}
作为旁注,将 Parent
定义为包装 Fooable
和 Barable
实例的依赖项意味着 Fooable
可以操纵 Barable
并相反.
您的实际要求中没有说明。如果你想防止这种情况发生,你应该为包含数据的上下文定义一个特定的 class 以及你想在两种契约(Fooable
和 Barable
之间共享的方法另一个 class 用于 ChildXXX subclasses.
的总合同
而不是在构造函数中传递 Parent
实例,而是传递 Context
实例。
你太依赖继承 IMO 了。 Clean Code 的一般规则是组合优先于继承。
你想要的是这样的:
interface Foo {
void foo();
}
interface Bar {
void bar();
}
interface FooBar extends Foo, Bar {}
有几种创建方法。
Parent 中的内部 classes 和工厂方法 class
Parent
class 不需要实现那些;它可以提供内部 classes 这样做,以便那些能够访问受保护的成员。
class Parent {
protected int neededByFoo;
protected int neededByBar;
class FooA implements Foo {
public void foo() {
doStuffWithNeededByFoo();
}
}
class FooB implements Foo {
public void foo() {
doStuffWithNeededByFoo();
}
}
// same for the BarA and BarB implementations
}
借助实用程序委托 class(与您的解决方案 B 不同)和 Parent
中的工厂方法,您可以将它们组合到实现这两个接口的实例中。
private static class FooBarDelegate implements FooBar {
Foo fooDelegate;
Bar barDelegate;
private FooBarDelegate(Foo f, Bar b) { fooDelegate = f; barDelegate = b; }
public void foo() { fooDelegate.foo(); }
public void bar() { barDelegate.bar(); }
}
public FooBar fooAbarA() {
return new FooBarDelegate(new FooA(), new BarA());
}
public FooBar fooBbarA() {
return new FooBarDelegate(new FooB(), new BarA());
}
public FooBar fooAbarB() {
return new FooBarDelegate(new FooA(), new BarB());
}
public FooBar fooBbarA() {
return new FooBarDelegate(new FooB(), new BarB());
}
}
Here's a running version of this code.
现在,内部 classes 本质上是组装成 FooBar
实例的策略。根本不需要subclass Parent
.
在界面中使用组合方法
您可能根本不想在 Parent
class 中进行组合,但在界面中:
interface FooBar extends Foo, Bar {
public static FooBar combine(Foo f, Bar b) {
return new FooBar() {
foo() { f.foo(); }
bar() { b.bar(); }
}
}
}
然后你会像这样使用它
Parent p = new Parent();
FooBar fb = FooBar.combine(new p.FooA(), new p.BarA());
fb = FooBar.combine(new p.FooA(), new p.BarB());
等等。
方法参考
因为 Foo
和 Bar
是函数式接口,您可以组合 Parent
对象的方法而不是使用内部 classes.
class Parent {
public void fooA() { // do stuff }
public void fooB() { // do stuff }
public void barA() { // do stuff }
public void barB() { // do stuff }
}
然后
FooBar fb = FooBar.combine(p::fooA, p::barA);
fb = FooBar.combine(p::fooA, p::barB);
// and so on
我有一个抽象 class Parent
,其中包含抽象方法 foo()
和 bar()
以及其他非抽象方法和字段。我需要创建 4 个 subclasses(以及后来的更多)来涵盖 foo()
和 bar()
上不同变体的每个组合:fooA()
、fooB()
、barA()
、barB()
。这些变体需要访问 Parent
的其他字段和方法。
换句话说,如果 Java 支持多重继承,那么我会有这样的东西:
abstract class Parent{
abstract foo(){}
abstract bar(){}
//other fields and methods that will be accessed foo and bar are PROTECTED
}
abstract class FooA extends Parent{
@Override
foo(){ ... }
}
abstract class FooB extends Parent{
@Override
foo(){ ... }
}
abstract class BarA extends Parent{
@Override
bar(){ ... }
}
abstract class BarB extends Parent{
@Override
bar(){ ... }
}
class ChildAA extends FooA, BarA{
}
class ChildAB extends FooA, BarB{
}
class ChildBA extends FooB, BarA{
}
class ChildBB extends FooB, BarB{
}
我找到了两种解决方案,每一种都有效,但差不多。有没有更好的方法来实现这种行为?我的解决方案如下:
1)第一个解决方案:
abstract class Parent {
foo(){
/* behaves like fooA */
}
//other fields and methods that will be accessed foo and bar are PROTECTED
}
class ChildAA extends Parent{
barA(){ ... }
}
class ChildAB extends Parent{
barB(){ ... }
}
class ChildBA extends ChildAA{
@Override
foo(){ /* behaves like fooB */ }
|
class ChildBB extends ChildAB{
@Override
foo(){ /* behaves like fooB */ }
}
问题在于它复制了 fooB()
的代码以及只有 fooB()
需要的所有其他方法。当需要更多变化时,问题会呈指数级恶化。
2) 环顾四周后,我找到了设计模式 Strategy,它可以用来实现行为但很尴尬,因为变体需要访问 Parent
的字段和方法:
abstract class Parent{
Fooable fooable;
Barable barable;
foo(){ fooable.foo(); }
bar(){ barable.bar(); }
//other fields and methods that will be accessed foo and bar are PUBLIC
}
abstract class ImplementableParent{
Parent p;
ImplementableParent(Parent p) { this.p = p; }
}
interface Fooable{
foo();
}
class FooA extends ImplementableParent implements Fooable{
FooA(Parent p){ super(p); }
@Override
foo(){ /* behaves like FooA */ }
}
class FooB extends ImplementableParent implements Fooable{
FooB(Parent p){ super(p); }
@Override
foo(){ /* behaves like FooB */ }
}
interface Barable{
bar();
}
class BarA extends ImplementableParent implements Barable{
BarA(Parent p) { super(p); }
@Override
bar() { /* behaves like BarA */ }
}
class BarB extends ImplementableParent implements Barable{
BarB(Parent p) { super(p); }
@Override
bar() { /* behaves like BarB */ }
}
class ChildAA extends Parent{
fooable = new FooA(this);
barable = new BarA(this);
}
class ChildAB extends Parent{
fooable = new FooA(this);
barable = new BarB(this);
}
class ChildBA extends Parent{
fooable = new FooB(this);
barable = new BarA(this);
}
class ChildBB extends Parent{
fooable = new FooB(this);
barable = new BarB(this);
}
这消除了重复的变体,并且可以扩展以容纳更多变体。但是现在Parent
的字段和方法变成了public,整个感觉很绕。我还担心性能开销,因为 FooA
、FooB
、BarA
和 BarB
间接访问 Parent
方法,尽管我没有测试过。
是否有更好的方法来实现该行为?
However, now the fields and methods of Parent are public and the whole thing feels very convoluted.
您的 Barable 和 Fooable 实现本身不保存上下文,因此它们必须使用上下文对象中的 public
方法(此处为 subclasses Parent
)查询和操作它。
但是只有 Parent
方法必须是 public,而不是它的字段。
例如,对于 Parent
和 FooA
实现来说,这将是一个公平的实现:
abstract class Parent{
private Fooable fooable; // internals
private Barable barable; // internals
private String sharedString; // internals
private Integer sharedInteger; // internals
// public access
public foo(){ fooable.foo(); }
public bar(){ barable.bar(); }
public String getSharedString(){
return sharedString;
}
public Integer getSharedInteger(){
return sharedInteger;
}
public String updateSharedData(String string, Integer integer){
// apply some logic and controls if required
this.string = string;
this.integer = integer;
}
}
class FooA extends ImplementableParent implements Fooable{
FooA(Parent p){
super(p);
}
@Override
foo(){
if (p.getSharedString().equals("...)){
// some logic
p.updateSharedData("new value", newIntegerValue);
}
}
}
作为旁注,将 Parent
定义为包装 Fooable
和 Barable
实例的依赖项意味着 Fooable
可以操纵 Barable
并相反.
您的实际要求中没有说明。如果你想防止这种情况发生,你应该为包含数据的上下文定义一个特定的 class 以及你想在两种契约(Fooable
和 Barable
之间共享的方法另一个 class 用于 ChildXXX subclasses.
的总合同
而不是在构造函数中传递 Parent
实例,而是传递 Context
实例。
你太依赖继承 IMO 了。 Clean Code 的一般规则是组合优先于继承。
你想要的是这样的:
interface Foo {
void foo();
}
interface Bar {
void bar();
}
interface FooBar extends Foo, Bar {}
有几种创建方法。
Parent 中的内部 classes 和工厂方法 class
Parent
class 不需要实现那些;它可以提供内部 classes 这样做,以便那些能够访问受保护的成员。
class Parent {
protected int neededByFoo;
protected int neededByBar;
class FooA implements Foo {
public void foo() {
doStuffWithNeededByFoo();
}
}
class FooB implements Foo {
public void foo() {
doStuffWithNeededByFoo();
}
}
// same for the BarA and BarB implementations
}
借助实用程序委托 class(与您的解决方案 B 不同)和 Parent
中的工厂方法,您可以将它们组合到实现这两个接口的实例中。
private static class FooBarDelegate implements FooBar {
Foo fooDelegate;
Bar barDelegate;
private FooBarDelegate(Foo f, Bar b) { fooDelegate = f; barDelegate = b; }
public void foo() { fooDelegate.foo(); }
public void bar() { barDelegate.bar(); }
}
public FooBar fooAbarA() {
return new FooBarDelegate(new FooA(), new BarA());
}
public FooBar fooBbarA() {
return new FooBarDelegate(new FooB(), new BarA());
}
public FooBar fooAbarB() {
return new FooBarDelegate(new FooA(), new BarB());
}
public FooBar fooBbarA() {
return new FooBarDelegate(new FooB(), new BarB());
}
}
Here's a running version of this code.
现在,内部 classes 本质上是组装成 FooBar
实例的策略。根本不需要subclass Parent
.
在界面中使用组合方法
您可能根本不想在 Parent
class 中进行组合,但在界面中:
interface FooBar extends Foo, Bar {
public static FooBar combine(Foo f, Bar b) {
return new FooBar() {
foo() { f.foo(); }
bar() { b.bar(); }
}
}
}
然后你会像这样使用它
Parent p = new Parent();
FooBar fb = FooBar.combine(new p.FooA(), new p.BarA());
fb = FooBar.combine(new p.FooA(), new p.BarB());
等等。
方法参考
因为 Foo
和 Bar
是函数式接口,您可以组合 Parent
对象的方法而不是使用内部 classes.
class Parent {
public void fooA() { // do stuff }
public void fooB() { // do stuff }
public void barA() { // do stuff }
public void barB() { // do stuff }
}
然后
FooBar fb = FooBar.combine(p::fooA, p::barA);
fb = FooBar.combine(p::fooA, p::barB);
// and so on