开发者

Is cleaner way to implement boolean logic that passes if either of two things happen?

开发者 https://www.devze.com 2023-03-28 08:01 出处:网络
This happens to me every once in a while and I always end up solving it the same way and then wishing for a cleaner way.

This happens to me every once in a while and I always end up solving it the same way and then wishing for a cleaner way.

I start out with a calls to related utility functions, followed by and update call.

SynchA();
SynchB();
UpdateLastTime();

Then later I add check boxes so I have:

if(synchA.Checked)
{
  SynchA();
}
if(synchB.Checked)
{
  SynchB();
}

BUT now I only want to call UpdateLastTime() of ONE OR BOTH the two executed so invariably I end up with:

bool synchHappened = false;
if(synchA.Checked)
{
  SynchA();
  synchHappe开发者_JAVA百科ned = true;
}
if(synchB.Checked)
{
  SynchB();
  synchHappened = true;
}
if(synchHappened)
{
  UpdateLastTime();
}

That final step always bothers me because I'm spreading this one bool around to three branches of logic.

Is there some obvious better approach to the above logic/scenario that I could use?


The main goal would be - each time as logic has changed - code should be affected at least as possible. So you've to structure such things once and then it will work for you.

In your particular case I would suggest to Keep It Simple (no Strategy Pattern, and so on), so extract and encapsulate a logic of switches into the properties. So each time as requirements will be changed - you've to update either logic of particular switch or main logic itself.

Switches with encapsulated rules:

bool IsUpdateLastTime
{
 get
 {
    // logic here even can be fully or partially injected 
    // as Func<bool>
    return this.IsSyncA || this.IsSyncB;
 }
}

bool IsSyncA { get { return synchA.Checked; } }
bool IsSyncB { get { return synchB.Checked; } }

Main logic:

if (this.IsUpdateLastTime)
{
  this.UpdateLastTime();
}


This kind of problem is where Rx is really useful, as you can combine several events into a single one. It can be done with something like this.

(Assuming winforms for this example, but it's similar with WPF etc, just by changing the event names/generic type arg for FromEvent.)

var synchAchecked = Observable.FromEvent<EventArgs>(synchA.CheckedChanged);
var synchBchecked = Observable.FromEvent<EventArgs>(synchB.CheckedChanged);
var merged = Observable.Merge(synchAchecked, synchBchecked);

synchAchecked.Subscribe(x => SynchA());
synchBchecked.Subscribe(x => SynchB());
merged.Subscribe(x => UpdateLastTime());


One might consider this pattern more compact (and possibly readable) although it still requires the separate variable.

bool syncHappened = false;
if(syncHappened |= synchA.Checked) SynchA();
if(syncHappened |= synchB.Checked) SynchB();
if(syncHappened) UpdateLastTime();


Some may not like this, but I find it very useful and clean. It's a bit odd, so the decision to use this is up to you.

UpdateLastTime(Either(SynchA(synchA.Checked), SynchB(synchB.Checked)));

private bool Either(bool first, bool second)
{
    return first || second;
}

This requires that SynchA(), SynchB() and UpdateLastTime() be modified to do no work if shouldRun is false, and return true or false depending whether the synch occurred.


A bit C centric, but:

if (checked_syncs & SYNC_A)
    SyncA();
if (checked_syncs & SYNC_B)
    SyncB();
if (checked_syncs)
    UpdateLastTime();

This has the advantage that the last check doesn't have to change (unless you run out of bits, in which case you can switch to a larger primitive type, or just use more than one). It also has the advantage of effectively doing all the ORs for UpdateLastTime() in parallel, so it is also a fast solution.

NOTE: Of course SYNC_A and SYNC_B have to be unique powers of two, and yes - this may break your encapsulation a bit, and assumes you can |= the condition when the check occurs (may not be possible, or beneficial over setting a boolean if you are talking about a specific GUI toolkit).

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号