수업의 모든 메서드를 특정 코드 블록으로 시작하는 우아한 방법이 있을까요?
모든 방법이 같은 방식으로 시작되는 수업이 있습니다.
class Foo {
public void bar() {
if (!fooIsEnabled) return;
//...
}
public void baz() {
if (!fooIsEnabled) return;
//...
}
public void bat() {
if (!fooIsEnabled) return;
//...
}
}
요?fooIsEnabled
수업의 모든 공개적인 방법을 위해 파트를 짜깁기?
것은 「Java」, 「Java」를 한 작업 입니다.java.lang.reflect.Proxy
모든 메서드 호출을 강제합니다.Foo
확인하다enabled
discloss.discloss.conf.
main
★★★★
public static void main(String[] args) {
Foo foo = Foo.newFoo();
foo.setEnabled(false);
foo.bar(); // won't print anything.
foo.setEnabled(true);
foo.bar(); // prints "Executing method bar"
}
Foo
★★★★★★★★★★★★★★★★★★:
public interface Foo {
boolean getEnabled();
void setEnabled(boolean enable);
void bar();
void baz();
void bat();
// Needs Java 8 to have this convenience method here.
static Foo newFoo() {
FooFactory fooFactory = new FooFactory();
return fooFactory.makeFoo();
}
}
FooFactory
링크:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class FooFactory {
public Foo makeFoo() {
return (Foo) Proxy.newProxyInstance(
this.getClass().getClassLoader(),
new Class[]{Foo.class},
new FooInvocationHandler(new FooImpl()));
}
private static class FooImpl implements Foo {
private boolean enabled = false;
@Override
public boolean getEnabled() {
return this.enabled;
}
@Override
public void setEnabled(boolean enable) {
this.enabled = enable;
}
@Override
public void bar() {
System.out.println("Executing method bar");
}
@Override
public void baz() {
System.out.println("Executing method baz");
}
@Override
public void bat() {
System.out.println("Executing method bat");
}
}
private static class FooInvocationHandler implements InvocationHandler {
private FooImpl fooImpl;
public FooInvocationHandler(FooImpl fooImpl) {
this.fooImpl = fooImpl;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Foo.class &&
!method.getName().equals("getEnabled") &&
!method.getName().equals("setEnabled")) {
if (!this.fooImpl.getEnabled()) {
return null;
}
}
return method.invoke(this.fooImpl, args);
}
}
}
다른 사람들이 지적한 것처럼, 당신이 걱정할 수 있는 몇 가지 방법만 있다면, 당신이 필요한 것을 위해 과잉 살상하는 것처럼 보입니다.
단, 다음과 같은 이점이 있습니다.
- , 그 는 '다'가 '다'이기 때문이다.
Foo
의 메서드 은 ""에enabled
교차 우려 사항을 점검합니다.대신 메서드의 코드는 메서드의 주요 목적이 무엇인지에 대해서만 걱정하면 됩니다. - 수 방법은 .
Foo
하는 " 。enabled
ㅇㅇㅇㅇㅇㅇㅇ.enabled
체크 동작은 새로 추가된 메서드에 의해 자동으로 상속됩니다. - 대한 관심이
enabled
체크, 한 곳에서 안전하게 작업하는 것은 매우 쉽습니다. - 내장된 Java 기능으로 AOP와 같은 동작을 할 수 있다는 것은 좋은 일입니다. 것은 아닙니다.
Spring
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★♪
공정하게 말하면 다음과 같은 단점이 있습니다.
- 프록시 호출을 처리하는 구현 코드 중 일부가 보기 흉합니다.또 은 '이 '내부 계급'이 ' 계급'이 '내부 계급'이 '내부 계급'이 있다'고도 있다.
FooImpl
업은못못 못못못다다 -
Foo
실장 클래스와 인터페이스라는2개의 장소에서 변경을 가할 필요가 있습니다.별일은 아니지만 아직 일이 좀 더 남았네요. - 프록시 호출은 무료가 아닙니다.일정한 퍼포먼스 오버헤드가 있습니다.일반용으로는 눈에 띄지 않습니다.상세한 것에 대하여는, 여기를 참조해 주세요.
편집:
Fabian Streitel의 코멘트는 위의 솔루션에서 두 가지 문제를 생각하게 했습니다.인정하건대, 나는 나 자신에 대해 만족하지 못합니다.
- 호출 핸들러는 마법 문자열을 사용하여 "getEnabled" 및 "setEnabled" 메서드의 "enabled-check"를 건너뜁니다.메서드 이름을 리팩터링하면 쉽게 파손될 수 있습니다.
- "enabled-check" 동작을 상속해서는 안 되는 새로운 메서드를 추가할 필요가 있는 경우 개발자가 이를 오해하기 쉬우며 적어도 매직 문자열을 추가하는 것을 의미합니다.
#1을 .BypassCheck
것)의할 때 할 수 있습니다.Foo
check "enabled check" 를 않은 입니다.이렇게 하면 마법의 끈이 전혀 필요 없고, 개발자가 이 특별한 경우에 새로운 방법을 올바르게 추가할 수 있게 됩니다.
주석 솔루션을 사용하면 코드는 다음과 같습니다.
main
★★★★
public static void main(String[] args) {
Foo foo = Foo.newFoo();
foo.setEnabled(false);
foo.bar(); // won't print anything.
foo.setEnabled(true);
foo.bar(); // prints "Executing method bar"
}
BypassCheck
★★★★
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BypassCheck {
}
Foo
★★★★★★★★★★★★★★★★★★:
public interface Foo {
@BypassCheck boolean getEnabled();
@BypassCheck void setEnabled(boolean enable);
void bar();
void baz();
void bat();
// Needs Java 8 to have this convenience method here.
static Foo newFoo() {
FooFactory fooFactory = new FooFactory();
return fooFactory.makeFoo();
}
}
FooFactory
링크:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class FooFactory {
public Foo makeFoo() {
return (Foo) Proxy.newProxyInstance(
this.getClass().getClassLoader(),
new Class[]{Foo.class},
new FooInvocationHandler(new FooImpl()));
}
private static class FooImpl implements Foo {
private boolean enabled = false;
@Override
public boolean getEnabled() {
return this.enabled;
}
@Override
public void setEnabled(boolean enable) {
this.enabled = enable;
}
@Override
public void bar() {
System.out.println("Executing method bar");
}
@Override
public void baz() {
System.out.println("Executing method baz");
}
@Override
public void bat() {
System.out.println("Executing method bat");
}
}
private static class FooInvocationHandler implements InvocationHandler {
private FooImpl fooImpl;
public FooInvocationHandler(FooImpl fooImpl) {
this.fooImpl = fooImpl;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Foo.class
&& !method.isAnnotationPresent(BypassCheck.class) // no magic strings
&& !this.fooImpl.getEnabled()) {
return null;
}
return method.invoke(this.fooImpl, args);
}
}
}
좋은 제안들이 많이 있어요.문제를 해결하기 위해 할 수 있는 일은 상태 패턴으로 생각하고 실행하는 것입니다.
이 코드 조각 좀 보세요아마 아이디어를 얻을 수 있을 거예요.이 시나리오에서는 객체의 내부 상태에 따라 메서드 구현 전체를 수정하려는 것처럼 보입니다.객체의 메서드의 합계가 동작으로 인식된다는 점에 유의하십시오.
public class Foo {
private FooBehaviour currentBehaviour = new FooEnabledBehaviour (); // or disabled, or use a static factory method for getting the default behaviour
public void bar() {
currentBehaviour.bar();
}
public void baz() {
currentBehaviour.baz();
}
public void bat() {
currentBehaviour.bat();
}
public void setFooEnabled (boolean fooEnabled) { // when you set fooEnabel, you are changing at runtime what implementation will be called.
if (fooEnabled) {
currentBehaviour = new FooEnabledBehaviour ();
} else {
currentBehaviour = new FooDisabledBehaviour ();
}
}
private interface FooBehaviour {
public void bar();
public void baz();
public void bat();
}
// RENEMBER THAT instance method of inner classes can refer directly to instance members defined in its enclosing class
private class FooEnabledBehaviour implements FooBehaviour {
public void bar() {
// do what you want... when is enabled
}
public void baz() {}
public void bat() {}
}
private class FooDisabledBehaviour implements FooBehaviour {
public void bar() {
// do what you want... when is desibled
}
public void baz() {}
public void bat() {}
}
}
마음에 들었으면 좋겠다!
P.D: 상태 패턴의 구현(문맥에 따라 전략이라고도 함)원칙은 똑같다).
네, 하지만 일이 좀 있어서 당신에게 얼마나 중요한지에 달렸어요.
후 를 할 수 .java.lang.reflect.Proxy
공유 부분을 실행한 후 조건부로 대리인을 호출하는 메서드를 사용하여 인터페이스를 구현합니다.
interface Foo {
public void bar();
public void baz();
public void bat();
}
class FooImpl implements Foo {
public void bar() {
//... <-- your logic represented by this notation above
}
public void baz() {
//... <-- your logic represented by this notation above
}
// and so forth
}
Foo underlying = new FooImpl();
InvocationHandler handler = new MyInvocationHandler(underlying);
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
handler);
의 ★★★★★★★★★★★★★★★★★.MyInvocationHandler
생략되어 .는, 「오류 처리」를 전제로 하고 있습니다).fooIsEnabled
액세스 가능한 장소에 정의되어 있습니다).
public Object invoke(Object proxy, Method method, Object[] args) {
if (!fooIsEnabled) return null;
return method.invoke(underlying, args);
}
믿을 수 없을 정도로 예쁘지는 않아요.하지만 다양한 코멘트와는 달리 저는 반복이 이런 밀도보다 더 중요하다고 생각하기 때문에 이 다소 이해하기 어려운 포장지를 코드 몇 줄에 로컬하게 추가함으로써 실제 클래스의 "느낌"을 낼 수 있습니다.
동적 프록시 클래스에 대한 자세한 내용은 Java 문서를 참조하십시오.
이 질문은 애스펙트 지향 프로그래밍과 밀접하게 관련되어 있습니다.Aspect J는 Java의 AOP 확장으로, 어떤 ISP를 얻을 수 있는지 확인할 수 있습니다.
Java에서 AOP를 직접 지원하지 않는 것으로 알고 있습니다.Template Method나 Strategy 등 이와 관련된 GOF 패턴이 몇 가지 있지만 코드 행은 실제로 저장되지 않습니다.
Java 및 기타 대부분의 언어에서는 함수에 필요한 반복 로직을 정의하고 적절한 타이밍에 호출하는 이른바 규율화된 코딩 방식을 채택할 수 있습니다.
public void checkBalance() {
checkSomePrecondition();
...
checkSomePostcondition();
}
그러나 이것은 당신의 경우에 맞지 않을 것입니다.왜냐하면 당신은 팩터 아웃 코드를 에서 반환할 수 있기를 원하기 때문입니다.checkBalance
등)를 서포트하는 에서는, 「(C/C++)」를 정의할 수 checkSomePrecondition
★★★★★★★★★★★★★★★★★」checkSomePostcondition
매크로로서 컴파일러를 기동하기 전에, 이러한 매크로를 프리프로세서로 간단하게 치환할 수 있습니다.
#define checkSomePrecondition \
if (!fooIsEnabled) return;
Java에는 이 기능이 없습니다.이것은 누군가에게 불쾌감을 줄 수 있지만, 나는 과거에 반복적인 코딩 작업을 자동화하기 위해 자동 코드 생성과 템플릿 엔진을 사용했다.Java 파일을 적절한 프리프로세서(예: Jinja2)로 컴파일하기 전에 처리하면 C에서 가능한 것과 유사한 작업을 수행할 수 있습니다.
순수 Java 접근법 가능
순수 Java 솔루션을 찾고 있다면 간결하지 않을 수 있습니다.다만, 프로그램의 일반적인 부분을 배제하고, 코드 중복이나 버그를 회피할 수 있습니다.이와 같은 작업을 수행할 수 있습니다(이것은 일종의 전략에서 영감을 얻은 패턴입니다).C# 및 Java 8 및 기능이 조금 다루기 쉬운 다른 언어에서는 이 접근법이 실제로 적절해 보일 수 있습니다.
public interface Code {
void execute();
}
...
public class Foo {
private bool fooIsEnabled;
private void protect(Code c) {
if (!fooIsEnabled) return;
c.execute();
}
public void bar() {
protect(new Code {
public void execute() {
System.out.println("bar");
}
});
}
public void baz() {
protect(new Code {
public void execute() {
System.out.println("baz");
}
});
}
public void bat() {
protect(new Code {
public void execute() {
System.out.println("bat");
}
});
}
}
현실세계의 시나리오처럼
산업용 로봇에 데이터 프레임을 보내기 위한 클래스를 개발 중입니다.로봇은 명령을 완료하는 데 시간이 걸립니다.명령어가 완료되면 컨트롤 프레임이 반환됩니다.이전 명령이 아직 실행 중일 때 새 명령이 수신되면 로봇이 손상될 수 있습니다.은 '''를 하고 있습니다.DataLink
로봇과 프레임을 주고받을 수 있는 클래스입니다.'가합니다.DataLink
★★★★★★ 。
가 " " 를 호출합니다.RobotController.left
,right
,up
★★★★★★★★★★★★★★★★★」down
만 아니라, 「」를 ,BaseController.tick
으로의 커맨드 하게 하기 , 「」를 유효하게 합니다.DataLink
★★★★★★ 。
interface Code {
void ready(DataLink dataLink);
}
class BaseController {
private DataLink mDataLink;
private boolean mReady = false;
private Queue<Code> mEnqueued = new LinkedList<Code>();
public BaseController(DataLink dl) {
mDataLink = dl;
}
protected void protect(Code c) {
if (mReady) {
mReady = false;
c.ready(mDataLink);
}
else {
mEnqueue.add(c);
}
}
public void tick() {
byte[] frame = mDataLink.readWithTimeout(/* Not more than 50 ms */);
if (frame != null && /* Check that it's an ACK frame */) {
if (mEnqueued.isEmpty()) {
mReady = true;
}
else {
Code c = mEnqueued.remove();
c.ready(mDataLink);
}
}
}
}
class RobotController extends BaseController {
public void left(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write(/* Create a byte[] that means 'left' by amount */);
}});
}
public void right(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write(/* Create a byte[] that means 'right' by amount */);
}});
}
public void up(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write(/* Create a byte[] that means 'up' by amount */);
}});
}
public void down(float amount) {
protect(new Code() { public void ready(DataLink dataLink) {
dataLink.write(/* Create a byte[] that means 'down' by amount */);
}});
}
}
이치노이 패턴은 DRY 패턴(반복하지 마세요)을 크게 깨트리고 있습니다.나는 이것이 이 반의 책임을 깬다고 믿는다.하지만 이것은 코드를 제어하는 방법에 따라 달라집니다.요. 로 전화하는 예요? 디로로 전화 ?? ????Foo
인턴instanceinstanceinstance?
내 생각에 당신은 다음과 같은 코드를 가지고 있을 것이다.
foo.bar(); // does nothing if !fooEnabled
foo.baz(); // does also nothing
foo.bat(); // also
이런 식으로 불러야 할 것 같아요
if (fooEnabled) {
foo.bat();
foo.baz();
...
}
그리고 깨끗하게 유지하세요.예를 들어 로깅:
this.logger.debug(createResourceExpensiveDump())
a logger
디버깅이 유효한지 아닌지는 스스로 묻지 않습니다.로그만 남아요.
대신에, 콜 클래스는 이것을 체크할 필요가 있습니다.
if (this.logger.isDebugEnabled()) {
this.logger.debug(createResourceExpensiveDump())
}
이고 이 할 수 는, 「」를 .IllegalStateException
이 전화가 불법이고 문제를 일으킨다면 그 이유가 설명되죠
IMHO에서 가장 우아하고 최고의 성능을 발휘하는 솔루션은 Foo를 두 개 이상 구현하고 다음을 작성하는 공장 방법을 사용하는 것입니다.
class Foo {
protected Foo() {
// Prevent direct instantiation
}
public void bar() {
// Do something
}
public static void getFoo() {
return fooEnabled ? new Foo() : new NopFoo();
}
}
class NopFoo extends Foo {
public void bar() {
// Do nothing
}
}
또는 변형:
class Foo {
protected Foo() {
// Prevent direct instantiation
}
public void bar() {
// Do something
}
public static void getFoo() {
return fooEnabled ? new Foo() : NOP_FOO;
}
private static Foo NOP_FOO = new Foo() {
public void bar() {
// Do nothing
}
};
}
sstan이 지적한 바와 같이 인터페이스를 사용하는 것이 좋습니다.
public interface Foo {
void bar();
static Foo getFoo() {
return fooEnabled ? new FooImpl() : new NopFoo();
}
}
class FooImpl implements Foo {
FooImpl() {
// Prevent direct instantiation
}
public void bar() {
// Do something
}
}
class NopFoo implements Foo {
NopFoo() {
// Prevent direct instantiation
}
public void bar() {
// Do nothing
}
}
다른 상황에 맞게 조정하십시오(매회 새로운 Foo를 작성하거나 동일한 인스턴스를 재사용하는 경우 등).
또 다른 접근법이 있습니다.
interface Foo {
public void bar();
public void baz();
public void bat();
}
class FooImpl implements Foo {
public void bar() {
//...
}
public void baz() {
//...
}
public void bat() {
//...
}
}
class NullFoo implements Foo {
static NullFoo DEFAULT = new NullFoo();
public void bar() {}
public void baz() {}
public void bat() {}
}
}
그러면 할 수 있어요.
(isFooEnabled ? foo : NullFoo.DEFAULT).bar();
당신은 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★isFooEnabled
a Foo
""를하는 "FooImpl
NullFoo.DEFAULT
그러면 콜이 다시 쉬워집니다.
Foo toBeUsed = isFooEnabled ? foo : NullFoo.DEFAULT;
toBeUsed.bar();
toBeUsed.baz();
toBeUsed.bat();
그나저나 이건 '늘 패턴'이라고 불려요.
@Colin의 답변에 대한 유사한 기능적 접근법에서는 Java 8의 람다 함수를 사용하여 조건부 기능 토글/디세이블 코드를 가드 메서드로 랩할 수 있습니다.executeIfEnabled
조건부로 실행할 코드를 전달할 수 있는 액션 람다를 받아들입니다.
이 방법으로는 코드 행이 저장되지 않지만, 이 방법을 드라이업(DRYUP)함으로써 다른 기능 전환 문제 및 로깅, 진단, 프로파일링 등의 디버깅 문제를 집중 관리할 수 있습니다.
여기서 람다를 사용하는 것의 한 가지 이점은 폐쇄가 과부하를 피하기 위해 사용될 수 있다는 것입니다.executeIfEnabled
★★★★★★ 。
예를 들어 다음과 같습니다.
class Foo {
private Boolean _fooIsEnabled;
public Foo(Boolean isEnabled) {
_fooIsEnabled = isEnabled;
}
private void executeIfEnabled(java.util.function.Consumer someAction) {
// Conditional toggle short circuit
if (!_fooIsEnabled) return;
// Invoke action
someAction.accept(null);
}
// Wrap the conditionally executed code in a lambda
public void bar() {
executeIfEnabled((x) -> {
System.out.println("Bar invoked");
});
}
// Demo with closure arguments and locals
public void baz(int y) {
executeIfEnabled((x) -> {
System.out.printf("Baz invoked %d \n", y);
});
}
public void bat() {
int z = 5;
executeIfEnabled((x) -> {
System.out.printf("Bat invoked %d \n", z);
});
}
테스트의 경우:
public static void main(String args[]){
Foo enabledFoo = new Foo(true);
enabledFoo.bar();
enabledFoo.baz(33);
enabledFoo.bat();
Foo disabledFoo = new Foo(false);
disabledFoo.bar();
disabledFoo.baz(66);
disabledFoo.bat();
}
다른 답변에서 지적했듯이 전략 설계 패턴은 이 코드를 단순화하기 위해 따라야 할 적절한 설계 패턴입니다.여기에서는 반사를 통한 메서드 호출을 사용하여 설명했지만 동일한 효과를 얻기 위해 사용할 수 있는 메커니즘은 얼마든지 있습니다.
class Foo {
public static void main(String[] args) {
Foo foo = new Foo();
foo.fooIsEnabled = false;
foo.execute("bar");
foo.fooIsEnabled = true;
foo.execute("baz");
}
boolean fooIsEnabled;
public void execute(String method) {
if(!fooIsEnabled) {return;}
try {
this.getClass().getDeclaredMethod(method, (Class<?>[])null).invoke(this, (Object[])null);
}
catch(Exception e) {
// best to handle each exception type separately
e.printStackTrace();
}
}
// Changed methods to private to reinforce usage of execute method
private void bar() {
System.out.println("bar called");
// bar stuff here...
}
private void baz() {
System.out.println("baz called");
// baz stuff here...
}
private void bat() {
System.out.println("bat called");
// bat stuff here...
}
}
java가 기능을 조금 더 잘한다면.가장 OOO의 솔루션은 foo가 활성화되어 있을 때만 호출되도록 단일 함수를 묶는 클래스를 만드는 것이라고 생각합니다.
abstract class FunctionWrapper {
Foo owner;
public FunctionWrapper(Foo f){
this.owner = f;
}
public final void call(){
if (!owner.isEnabled()){
return;
}
innerCall();
}
protected abstract void innerCall();
}
후, 「」, 「」를 실장합니다.bar
,baz
★★★★★★★★★★★★★★★★★」bat
「어나니머스 클래스」로 확장되는 FunctionWrapper
class Foo {
public boolean fooIsEnabled;
public boolean isEnabled(){
return fooIsEnabled;
}
public final FunctionWrapper bar = new FunctionWrapper(this){
@Override
protected void innerCall() {
// do whatever
}
};
public final FunctionWrapper baz = new FunctionWrapper(this){
@Override
protected void innerCall() {
// do whatever
}
};
// you can pass in parms like so
public final FunctionWrapper bat = new FunctionWrapper(this){
// some parms:
int x,y;
// a way to set them
public void setParms(int x,int y){
this.x=x;
this.y=y;
}
@Override
protected void innerCall() {
// do whatever using x and y
}
};
}
다른 아이디어
glgl의 무효 솔루션을 사용하여FooImpl
★★★★★★★★★★★★★★★★★」NullFoo
다음 클래스의 내부 클래스(프라이빗 컨스트럭터 포함)
class FooGateKeeper {
public boolean enabled;
private Foo myFooImpl;
private Foo myNullFoo;
public FooGateKeeper(){
myFooImpl= new FooImpl();
myNullFoo= new NullFoo();
}
public Foo getFoo(){
if (enabled){
return myFooImpl;
}
return myNullFoo;
}
}
' '기억하다', '기억하다', '기억하다', '기억하다', 할 필요가 없습니다.(isFooEnabled ? foo : NullFoo.DEFAULT)
.
Foo가 활성화되어 있지 않으면 클래스는 아무것도 하지 않는 것 같기 때문에 Foo 인스턴스를 만들거나 가져오는 높은 수준에서 표현해 보는 것은 어떨까요?
class FooFactory
{
static public Foo getFoo()
{
return isFooEnabled ? new Foo() : null;
}
}
...
Foo foo = FooFactory.getFoo();
if(foo!=null)
{
foo.bar();
....
}
이것은 isFooEnabled가 상수인 경우에만 작동합니다.일반적인 경우 주석을 직접 작성할 수 있습니다.
Java 구문은 잘 모릅니다.Java에는 다형성, 정적 속성, 추상 클래스 및 메서드가 있다고 가정합니다.
public static void main(String[] args) {
Foo.fooIsEnabled = true; // static property, not particular to a specific instance
Foo foo = new bar();
foo.mainMethod();
foo = new baz();
foo.mainMethod();
foo = new bat();
foo.mainMethod();
}
public abstract class Foo{
static boolean fooIsEnabled;
public void mainMethod()
{
if(!fooIsEnabled)
return;
baMethod();
}
protected abstract void baMethod();
}
public class bar extends Foo {
protected override baMethod()
{
// bar implementation
}
}
public class bat extends Foo {
protected override baMethod()
{
// bat implementation
}
}
public class baz extends Foo {
protected override baMethod()
{
// baz implementation
}
}
기본적으로 플래그가 설정되어 있으면 함수 호출을 건너뜁니다.그래서 제 해결책은 바보같을 것 같지만, 여기 있습니다.
Foo foo = new Foo();
if (foo.isEnabled())
{
foo.doSomething();
}
다음은 함수를 실행하기 전에 몇 가지 코드를 실행하려는 경우에 대비한 단순 프록시의 구현입니다.
class Proxy<T>
{
private T obj;
private Method<T> proxy;
Proxy(Method<T> proxy)
{
this.ojb = new T();
this.proxy = proxy;
}
Proxy(T obj, Method<T> proxy)
{
this.obj = obj;
this.proxy = proxy;
}
public T object ()
{
this.proxy(this.obj);
return this.obj;
}
}
class Test
{
public static void func (Foo foo)
{
// ..
}
public static void main (String [] args)
{
Proxy<Foo> p = new Proxy(Test.func);
// how to use
p.object().doSomething();
}
}
class Foo
{
public void doSomething ()
{
// ..
}
}
또 다른 해결책은 위임자를 사용하는 것입니다(기능 포인터)를 사용하는 것입니다.처음에 검증을 실시하고 다음으로 호출하는 함수(파라미터)에 따라 관련 메서드를 호출하는 고유한 메서드를 사용할 수 있습니다.C# 코드:
internal delegate void InvokeBaxxxDelegate();
class Test
{
private bool fooIsEnabled;
public Test(bool fooIsEnabled)
{
this.fooIsEnabled = fooIsEnabled;
}
public void Bar()
{
InvokeBaxxx(InvokeBar);
}
public void Baz()
{
InvokeBaxxx(InvokeBaz);
}
public void Bat()
{
InvokeBaxxx(InvokeBat);
}
private void InvokeBaxxx(InvokeBaxxxDelegate invoker)
{
if (!fooIsEnabled) return;
invoker();
}
private void InvokeBar()
{
// do Invoke bar stuff
Console.WriteLine("I am Bar");
}
private void InvokeBaz()
{
// do Invoke bar stuff
Console.WriteLine("I am Baz");
}
private void InvokeBat()
{
// do Invoke bar stuff
Console.WriteLine("I am Bat");
}
}
언급URL : https://stackoverflow.com/questions/31121513/is-there-an-elegant-way-to-make-every-method-in-a-class-start-with-a-certain-blo
'source' 카테고리의 다른 글
Mac에 설치한 후 ALTER USER 문을 사용하여 MySQL 루트 암호 재설정 (0) | 2022.10.01 |
---|---|
벤더의 규모를 초과 (0) | 2022.10.01 |
배열 반복 중 현재 요소가 마지막 요소인지 확인하는 중 (0) | 2022.10.01 |
"forEach" 함수에서 "return" 키워드는 무엇을 의미합니까? (0) | 2022.10.01 |
Mac OS X에서 MySQL을 제거하려면 어떻게 해야 합니까? (0) | 2022.10.01 |