我正在努力实现这个效果:
getFileName()
这似乎是一个不可避免的难题,因为:
Singleton的大部分实现都是基于静态的(纯static class;或ENUM with a static parameter passing)
静态类/方法/块不能调用非静态方法...
...并且使getFileName()
静态将确保它不能使用继承覆盖!
如何实施此设计? (如果有更好的模式,我愿意改变设计)
答案 0 :(得分:2)
这意味着Singleton
不是你真正的问题,它是根据类型询问获得正确的类!
您的设计与您尝试的方式紧密耦合。您需要将Service
与服务的Consumers
完全分离,Singleton
在此练习中并不重要。
这正是Guice
创建的问题类型,它能够根据绑定中的其他类类型提供注入的类。那说......
大多数人都没有意识到Java始终通过DI
支持Constructor
。 Guice
使得硬编码更少,但它仍然是注入实例的依赖项。
Guice
通过基于类类型注入正确的服务来实现这一点。但是可以在没有任何DI
框架/库的情况下完成。如果您的案件使用Guice
被视为重手,那么仍然可以轻松完成。
public class Solution
{
static class Singleton
{
public static final Singleton INSTANCE;
static { INSTANCE = new Singleton(); }
private Singleton() { /* this is important */ }
public void doWhatever(@Nonnull final B b) { /* whatever */ }
public void doWhatever(@Nonnull final C c) { /* whatever */ }
}
static abstract class A
{
private final Singleton s;
public A(final Singleton s) { this.s = s; }
public abstract String getFilename();
}
static class B extends A
{
public B(final Singleton s) { super(s); }
@Override
public String getFilename() { /* code goes here */ }
}
static class C extends A
{
public C(final Singleton s) { super(s); }
@Override
public String getFilename() { /* code goes here */ }
}
}
Singleton
模式应隐藏在Factory
模式后面。你的消费者需要拥有1和只有1的人不应该关心是否有1和只有1.他们应该只关心那个对象符合某个界面的某些契约。
我的实现是一个在静态块中创建的天真Factory
。大多数是在第一次使用时创建的,这不是更好。
使用Enum
创建Singleton
个对象是对Enum
语义的误用和反模式,无法正确进行单元测试。
与所有静态实用程序类方法相同,无法对其他实现进行单元测试或替换。 这两者的结合是完全可憎的,这是不可能进行单元测试和维持完整的噩梦!
A
的哪个子类很简单:这就是上面的代码所示的重载。
其他任何事情做得不对。 instanceof
失败,reflection
更大失败。
可以使用重载方法,泛型或适当的设计模式来选择基于Type
的逻辑。
Strategy
模式可以轻松解决这个问题,并使N
个子类在运行时可管理和可扩展。
答案 1 :(得分:0)
我认为你需要决定S是否使用A或A是否使用S.
如果S使用A,那么A可以是基类或接口,S将有一个接受A的实例的方法,这些方法被getfileName()
的正确实现覆盖。
如果A使用S,则A应该是getFileName()
的抽象,强制构造一个实现,它应该在内部调用它尚未定义的getFileName()
将其作为一个传递S的论据。
单身人士是面向对象解决方案和非面向对象解决方案之间的粘合剂,因此您可以避免这个难题
将对象传递给非面向对象的单例“实用程序例程”
将已解析的参数传递给非面向对象的单例“实用程序例程”
第一项技术的示例代码
// this could be abstract class too, as long as getName() is abstract
public interface Nameable
public String getName();
}
public enum Utility {
INSTANCE;
public static deleteByName(Nameable nameable) {
createBackup(nameable.getName());
updateIntentLog(nameable.getName());
removeFile(nameable.getName());
updateAuditLog(nameable.getName());
}
}
或
public abstract class Nameable {
public abstract String getName();
public void delete() {
Utility.INSTANCE.deleteFile(getName());
}
}
public enum Utility {
INSTANCE;
public void deleteFile(String name) {
...
}
}
答案 2 :(得分:-1)