重构单身过度使用 [英] Refactoring Singleton Overuse

查看:90
本文介绍了重构单身过度使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天我有一个顿悟,这是我做错了一切。一些历史:我继承了一个C#应用程序,这真是一个静态方法的集合,一个完全程序上的乱码的C#代码。当时我所了解的最好,我重构了这些,带来了大量的大学后的OOP知识。为了做一个很长的故事,代码中的许多实体已经证明是单身人士。



今天我意识到我需要3个新的课程, Singleton模式匹配其余的软件。如果我一直在翻滚这个滑坡,最终我的申请中的每一个类都将是Singleton,这与原始的静态方法真的是没有逻辑上的区别。



需要帮助反思这个。我知道依赖注入,这通常是打破Singleton诅咒的策略。但是,我有一些与这个重构相关的具体问题,以及所有关于这样做的最佳做法。


  1. 使用静态变量封装配置信息?我有一个大脑阻止使用静态,我认为这是由于早期的OO类在大学里教授说静态是坏的。但是,每当我访问它时,是否应该重新配置该类?当访问硬件时,可以静态指向所需的地址和变量,或者我应该持续执行 Open() Close() 操作?


  2. 现在我有一个方法作为控制器。具体来说,我连续轮询多个外部仪器(通过硬件驱动程序)的数据。这种类型的控制器应该是这样的方式,还是应该在程序启动时为每个仪器产生单独的线程?如果后者,我该如何使这个面向对象?应该创建一个名为 Instrumentalistener InstrumentBListener 的类?还是有一些标准的方法来处理这个问题?


  3. 是否有更好的方式进行全局配置?现在我只需要在代码中自由地洒上$ code> Configuration.Instance.Foo 。几乎每个班都使用它,所以也许保持它是一个单身人士。任何想法?


  4. 我的很多课程都是像 SerialPortWriter DataFileWriter ,它们必须坐在等待这个数据流入。由于它们在整个时间内都处于活动状态,所以我应该如何排列这些数据,以便监听数据进入时产生的事件?


有关如何摆脱单身人士和其他模式过度使用的任何其他资源,书籍或评论都将有所帮助。

解决方案

好的,这是我最好的一枪攻击这个问题:



(1)静态



您可能遇到的 static 的问题是不同的东西在.NET中说,C ++。静态基本上意味着它可以在类本身上访问。至于它的可接受性 id,这个更多的东西你可以用来做一个类的非实例特定的操作。或者只是一般的东西,如 Math.Abs​​(...)。您应该使用的全局配置可能是一个静态访问属性来保存当前/主动配置。也可能是一些用于加载/保存设置配置的静态类,但是配置应该是一个对象,所以它可以传递给操纵等等。
public class MyConfiguration
{
public const string DefaultConfigPath =./config.xml;

  protected static MyConfiguration _current; 
public static MyConfiguration当前
{
get
{
if(_current == null)
加载(DefaultConfigPath);
return _current;
}
}

public static MyConfiguration Load(string path)
{
//在这里加载
_current = loadedConfig;
return loadedConfig;
}

//静态保存功能

// ***********非静态成员******* ** //

public string MyVariable {get;组;



(2)控制器/硬件



您应该查看一个反应式的方法, IObserver IObservable<> ,它是反应框架(Rx)



另一种方法是使用ThreadPool来调度轮询任务,因为您可能会获得大量的线程你有很多硬件来池。在使用任何种类的线程之前,请确保了解更多信息。制作错误很容易,甚至可能无法实现。 本书是一个优秀的来源,将会教你很多。



无论哪种方式,您应该可以构建服务(只是一个名称)来管理您的硬件,负责收集有关服务的信息(基本上是模型模式)。从那里,您的中央控制器可以使用它们访问控制器中的程序逻辑的数据,以及服务中的硬件逻辑。



(3)全局配置



我可能在第1点触及了这个主题,但通常这是我们去哪里,如果你发现自己打字太多,你总是可以拉出来假设 .Instance 是一个对象。

  MyConfiguration cfg = MyConfiguration.Current 
cfg.Foo // etc ...

(4 )聆听数据



反过来的框架可以帮助你,或者你可以建立一个事件驱动模型,它使用传入数据的触发器。这将确保您不会阻塞线程,直到数据进来。它可以大大降低应用程序的复杂性。


Today I had an epiphany, and it was that I was doing everything wrong. Some history: I inherited a C# application, which was really just a collection of static methods, a completely procedural mess of C# code. I refactored this the best I knew at the time, bringing in lots of post-college OOP knowledge. To make a long story short, many of the entities in code have turned out to be Singletons.

Today I realized I needed 3 new classes, which would each follow the same Singleton pattern to match the rest of the software. If I keep tumbling down this slippery slope, eventually every class in my application will be Singleton, which will really be no logically different from the original group of static methods.

I need help on rethinking this. I know about Dependency Injection, and that would generally be the strategy to use in breaking the Singleton curse. However, I have a few specific questions related to this refactoring, and all about best practices for doing so.

  1. How acceptable is the use of static variables to encapsulate configuration information? I have a brain block on using static, and I think it is due to an early OO class in college where the professor said static was bad. But, should I have to reconfigure the class every time I access it? When accessing hardware, is it ok to leave a static pointer to the addresses and variables needed, or should I continually perform Open() and Close() operations?

  2. Right now I have a single method acting as the controller. Specifically, I continually poll several external instruments (via hardware drivers) for data. Should this type of controller be the way to go, or should I spawn separate threads for each instrument at the program's startup? If the latter, how do I make this object oriented? Should I create classes called InstrumentAListener and InstrumentBListener? Or is there some standard way to approach this?

  3. Is there a better way to do global configuration? Right now I simply have Configuration.Instance.Foo sprinkled liberally throughout the code. Almost every class uses it, so perhaps keeping it as a Singleton makes sense. Any thoughts?

  4. A lot of my classes are things like SerialPortWriter or DataFileWriter, which must sit around waiting for this data to stream in. Since they are active the entire time, how should I arrange these in order to listen for the events generated when data comes in?

Any other resources, books, or comments about how to get away from Singletons and other pattern overuse would be helpful.

解决方案

Alright, here's my best shot at attacking this question:

(1) Statics

The Problem with static that you may be having is that it means different things in .NET and say, C++. Static basically means it's accessible on the class itself. As for it's acceptability id say it's more of something you'd use to do non-instance specific operations on a class. Or just general things like Math.Abs(...). What you should use for a global config is probably a statically accessed property for holding the current/active configuration. Also maybe some static classes for loading/saving setting the config, however the config should be an Object so it can be passed around manipulated, etc. public class MyConfiguration { public const string DefaultConfigPath = "./config.xml";

  protected static MyConfiguration _current;
  public static MyConfiguration Current
  {
    get
    {
      if (_current == null)
        Load(DefaultConfigPath);
      return _current;
    }
  }

  public static MyConfiguration Load(string path)
  {
    // Do your loading here
    _current = loadedConfig;
    return loadedConfig; 
  }

  // Static save function

  //*********** Non-Static Members *********//

  public string MyVariable { get; set; }
  // etc..
}

(2) Controller/Hardware

You should probably look into a reactive approach, IObserver<> or IObservable<>, it's part of the Reactive Framework (Rx).

Another approach is using a ThreadPool to schedule your polling tasks, as you may get a large number of threads if you have a lot of hardware to pool. Please make sure before using any kind of Threading to learn a lot about it. It's very easy to make mistakes you may not even realize. This Book is an excelent source and will teach you lots.

Either way you should probably build services (just a name really) for managing your hardware which are responsible for collecting information about a service (essentially a model-pattern). From there your central controller can use them to access the data keeping the program logic in the controller, and the hardware logic in the service.

(3) Global Configuration

I may have touched this subject in point #1 but generally that's where we go, if you find yourself typing too much you can always pull it out of there assuming the .Instance is an object.

MyConfiguration cfg = MyConfiguration.Current
cfg.Foo // etc...

(4) Listening For data

Again the reactive framework could help you out, or you could build up an event-driven model that uses triggers for incoming data. This will make sure you're not blocking on a thread till data comes in. It can reduce the complexity of your application greatly.

这篇关于重构单身过度使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆